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

1830 lines
48 KiB
C++

#include "stdafx.h"
#include "krenderobjectMesh.h"
#include "krenderobjectEtc.h"
#include "K3DCamera.h"
#include "KRenderDeviceDX.h"
#include "KDeviceManager.h"
#include "KResourceManager.h"
//#include "K3DFrustum.h"
#include "GameDefine.h"
#include "KResource.h"
#include "KViewport.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KCameraSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KCameraSeq::KCameraSeq()
{
m_ViewCamera = new K3DCamera;
m_ViewCamera->Reset();
}
KCameraSeq::~KCameraSeq()
{
SAFE_DELETE(m_ViewCamera);
}
void KCameraSeq::SetRes( K3DResCamera *pRes)
{
m_spRes = pRes;
if(m_spRes != NULL)
{
m_interval.Expand( m_spRes->GetInterval() );
}
}
void *KCameraSeq::Perform( KID id, KArg& msg )
{
_CID( REQ_INTERSECTIONLINE );
_CID( SET_CAMERARENDER );
_CID( GET_CAMERASEQ );
if ( id == id_REQ_INTERSECTIONLINE )
{
realizeTime();
KMsgREQ_INTERLINE *reqmsg = static_cast<KMsgREQ_INTERLINE*>(&msg);
int scrx = reqmsg->nScrx;
int scry = reqmsg->nScry;
KViewportObject *pViewport = reqmsg->pViewport;
float fNearClip = pViewport->GetNearClip();
float fFarClip = pViewport->GetFarClip();
float scx = static_cast<float>(scrx - pViewport->GetViewportX()) / static_cast<float>(pViewport->GetViewportWidth()-1) * 2.f - 1.f;
float scy = -(static_cast<float>(scry - pViewport->GetViewportY()) / static_cast<float>(pViewport->GetViewportHeight()-1) * 2.f - 1.f);
// get inverse of the camera view matrix into invMat
K3DMatrix invMat;
K3DMatrixInverse( invMat, m_matView );
K3DVertex vtx;
float sx = (scx)*fNearClip*tanf(m_fFOV*pViewport->GetVertexAspect()*0.5f);
float sy = (scy)*fNearClip*tanf(m_fFOV*0.5f);
vtx.x = sx; vtx.y = sy; vtx.z = -fNearClip;
K3DVectorTransform(reqmsg->vNear, vtx, invMat);
sx = (scx)*fFarClip*tanf(m_fFOV*pViewport->GetVertexAspect()*0.5f);
sy = (scy)*fFarClip*tanf(m_fFOV*0.5f);
vtx.x = sx; vtx.y = sy; vtx.z = -fFarClip;
K3DVectorTransform(reqmsg->vFar, vtx, invMat);
return (void*)1;
}
else if( id == id_SET_CAMERARENDER )
{
KMsgSET_CAMERARENDER *reqmsg = static_cast<KMsgSET_CAMERARENDER*>(&msg);
m_bRenderFlag = reqmsg->bRenderFlag;
return (void*)1;
}
else if ( id == id_GET_CAMERASEQ )
{
KMsgGET_CAMERASEQ *reqmsg = static_cast<KMsgGET_CAMERASEQ*>(&msg);
reqmsg->pCamSeq = this;
return (void*)1;
}
return NULL;
}
void KCameraSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
if( !m_bRenderFlag ) return;
realizeTime();
K3DMatrix projection;
if( m_ViewCamera->IsCoordinateRightHand() )
K3DMatrixPerspectiveFovRH( projection, m_fFOV,
viewport->GetVertexAspect(), viewport->GetNearClip(), viewport->GetFarClip() );
else
K3DMatrixPerspectiveFovLH( projection, m_fFOV,
viewport->GetVertexAspect(), viewport->GetNearClip(), viewport->GetFarClip() );
viewport->SetCamera(m_ViewCamera);
}
KSeqObject* KCameraSeq::Clone()
{
KCameraSeq *obj = new KCameraSeq;
obj->SetRes( m_spRes );
return obj;
}
void KCameraSeq::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime ) return;
m_dwRealizedTime = m_dwTime;
K3DResCamera::Key *key1 = NULL, *key2 = NULL;
m_spRes->GetData( m_dwTime, key1, key2 );
K3DVector respos, resview, resup;
if ( key2 != NULL )
{
int ctime = m_dwTime - key1->time;
float ratio = (float)ctime / float(key2->time - key1->time);
K3DVectorLerp( respos, key1->pos, key2->pos, ratio );
K3DVectorLerp( resview, key1->view, key2->view, ratio );
K3DVectorLerp( resup, key1->up, key2->up, ratio );
m_fFOV = key1->fov + ((key2->fov - key1->fov) * ratio);
}
else
{
respos = key1->pos;
resview = key1->view;
resup = key1->up;
m_fFOV = key1->fov;
}
K3DVector at = respos + resview;
m_vCamPos = respos;
K3DMatrixLookAtRH( m_matView, respos, at, resup );
m_ViewCamera->SetCamPos(m_vCamPos.x, m_vCamPos.y, m_vCamPos.z);
m_ViewCamera->SetTargetPos(at.x, at.y, at.z);
m_ViewCamera->SetUpVector(resup.x, resup.y, resup.z);
m_ViewCamera->SetFOV(m_fFOV);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KLightSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KLightSeq::KLightSeq()
{
}
KLightSeq::~KLightSeq()
{
}
void KLightSeq::SetRes( K3DResLight *pRes )
{
m_spRes = pRes;
if(m_spRes != NULL)
{
m_interval.Expand( m_spRes->GetInterval() );
}
}
void * KLightSeq::Perform( KID id, KArg& msg )
{
_CID( REQ_LIGHT );
if( id == id_REQ_LIGHT )
{
K3DResLight::Key *key1 = NULL, *key2 = NULL;
m_spRes->GetData( 0, key1, key2 );
if ( key2 != NULL )
{
int ctime = m_dwTime - key1->time;
float ratio = (float)ctime / float(key2->time - key1->time);
memcpy( &m_Light, &key1->light, sizeof(m_Light) );
K3DVectorLerp( m_Light.position, key1->light.position, key2->light.position, ratio );
K3DVectorLerp( m_Light.direction, key1->light.direction, key2->light.direction, ratio );
K3DColorLerp( m_Light.diffuse, key1->light.diffuse, key2->light.diffuse, ratio );
m_Light.range = key1->light.range + ((key2->light.range - key1->light.range) * ratio);
}
else
{
memcpy( &m_Light, &key1->light, sizeof(m_Light) );
}
KMsgREQ_LIGHT *pmsg = static_cast<KMsgREQ_LIGHT*>(&msg);
pmsg->m_pLightList.push_back( &m_Light );
return (void*)1;
}
return NULL;
}
void KLightSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
K3DResLight::Key *key1 = NULL, *key2 = NULL;
m_spRes->GetData( m_dwTime, key1, key2 );
if ( key2 != NULL )
{
int ctime = m_dwTime - key1->time;
float ratio = (float)ctime / float(key2->time - key1->time);
memcpy( &m_Light, &key1->light, sizeof(m_Light) );
K3DVectorLerp( m_Light.position, key1->light.position, key2->light.position, ratio );
K3DVectorLerp( m_Light.direction, key1->light.direction, key2->light.direction, ratio );
K3DColorLerp( m_Light.diffuse, key1->light.diffuse, key2->light.diffuse, ratio );
m_Light.range = key1->light.range + ((key2->light.range - key1->light.range) * ratio);
}
else
{
memcpy( &m_Light, &key1->light, sizeof(m_Light) );
}
viewport->AddLight( &m_Light );
}
KSeqObject* KLightSeq::Clone()
{
KLightSeq *obj = new KLightSeq;
obj->SetRes( m_spRes );
return obj;
}
void KLightSeq::realizeTime()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KSpriteSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KSpriteSeq::KSpriteSeq()
{
K3DMatrixIdentity(m_matLocal);
}
KSpriteSeq::~KSpriteSeq()
{
}
int KSpriteSeq::GetFrameCount()
{
return m_spRes->GetKeyCount();
}
KResSprite *KSpriteSeq::GetFrame( int nFrame )
{
return m_spRes->GetSpriteByFrame(nFrame);
}
int KSpriteSeq::GetCurrentIndex()
{
return m_spRes->GetIndexNumber(m_dwTime);
}
KResSprite* KSpriteSeq::GetCurrentFrame()
{
KResSpriteAnimation::Key *key1 = NULL, *key2 = NULL;
m_spRes->GetData( m_dwTime, key1, key2 );
if(key1)
return key1->spSprite;
return NULL;
}
LPCSTR KSpriteSeq::GetSeqName()
{
return m_spRes->GetName();
}
void KSpriteSeq::SetRes( KResSpriteAnimation *res )
{
assert(m_spRes == NULL);
m_spRes = res;
if(m_spRes != NULL)
{
m_interval = m_spRes->GetInterval();
}
}
KResSpriteAnimation* KSpriteSeq::GetRes()
{
return m_spRes;
}
void * KSpriteSeq::Perform( KID id, KArg& msg )
{
_CID( SET_RENDER_SIZE );
if( id == id_SET_RENDER_SIZE )
{
KMsgSET_RENDER_SIZE *pmsg = static_cast<KMsgSET_RENDER_SIZE*>(&msg);
m_sizeRender = pmsg->sizeRender;
if ( m_spRes != NULL )
{
int nFrames = m_spRes->GetKeyCount();
for ( int i=0 ; i<nFrames ; ++i )
{
KResSpriteAnimation::Key &key = m_spRes->GetKey( i );
key.spSprite->SetSize( static_cast<float>(m_sizeRender.cx), static_cast<float>(m_sizeRender.cy) );
}
}
return (void*)1;
}
return NULL;
}
void KSpriteSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
KResSpriteAnimation::Key *key1 = NULL, *key2 = NULL;
m_spRes->GetData( m_dwTime, key1, key2 );
K3DPoint offset = key1->spSprite->GetOffset();
K3DMatrix mat = m_matLocal;
mat._41 += offset.x;
mat._42 += offset.y;
K3DMatrix matTrans = key1->spSprite->GetTransform();
mat *= matTrans;
if ( m_pMatAttach != NULL && m_pMatParent != NULL )
{
K3DMatrix matTemp;
K3DMatrixMultiply( matTemp, *m_pMatAttach, *m_pMatParent );
K3DMatrixMultiply( m_matResult, m_matLocal, matTemp );
}
else if ( m_pMatParent != NULL )
K3DMatrixMultiply( m_matResult, m_matLocal, *m_pMatParent );
else
m_matResult = m_matLocal;
m_prSprite.SetRes(key1->spSprite );
m_prSprite.SetVisibility(m_fMasterVisibility * key1->spSprite->GetVisibility());
m_prSprite.SetTransform(m_matResult);
//m_prSprite.UpdateSprite();
viewport->Register( &m_prSprite );
}
KSeqObject* KSpriteSeq::Clone()
{
KSpriteSeq *obj = new KSpriteSeq;
obj->SetRes( m_spRes );
return obj;
}
void KSpriteSeq::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime ) return;
m_dwRealizedTime = m_dwTime;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KEventBoxSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KEventBoxSeq::KEventBoxSeq()
{
m_nType = KEVTYPE_BOX;
}
KEventBoxSeq::~KEventBoxSeq()
{
}
KSeqObject *KEventBoxSeq::Clone()
{
KEventBoxSeq *obj = new KEventBoxSeq;
obj->SetRes( m_spRes );
return obj;
}
const char *KEventBoxSeq::GetName()
{
if ( m_spRes != NULL )
{
return m_spRes->GetName();
}
return NULL;
}
void KEventBoxSeq::SetRes( K3DResEventBox *res )
{
assert(m_spRes == NULL);
m_spRes = res;
if ( m_spRes != NULL )
{
m_interval = m_spRes->GetInterval();
}
}
void KEventBoxSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
//realizeTime();
//m_bCube.Render( viewport );
}
const K3DBoundRotCube &KEventBoxSeq::GetCube()
{
realizeTime();
return m_bCube;
}
void *KEventBoxSeq::Perform( KID id, KArg& msg )
{
_CID( REQ_EVBOX );
if ( id == id_REQ_EVBOX )
{
KMsgREQ_EVBOX *reqmsg = static_cast<KMsgREQ_EVBOX*>(&msg);
reqmsg->AddBox( this );
return (void*)1;
}
return NULL;
}
void KEventBoxSeq::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime ) return;
m_dwRealizedTime = m_dwTime;
if ( m_spRes != NULL )
{
m_spRes->GetData( m_dwTime, &m_bCube );
}
}
void KEventBoxSeq::SetParentTransform( const K3DMatrix *pMatParent, const K3DMatrix *pMatAttach, BOOL bRotationLock )
{
KEventSeq::SetParentTransform( pMatParent, pMatAttach, bRotationLock );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KEventPointSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool KEventPointSeq::m_sIsRender = false;
KEventPointSeq::KEventPointSeq()
{
m_nType = KEVTYPE_BOX;
m_bCube = K3DBoundRotCube( -1, 1, -1, 1, -1, 1 );
K3DMatrixIdentity( m_matPoint );
}
KEventPointSeq::~KEventPointSeq()
{
}
KSeqObject *KEventPointSeq::Clone()
{
KEventPointSeq *obj = new KEventPointSeq;
obj->SetRes( m_spRes );
return obj;
}
const char *KEventPointSeq::GetName()
{
if ( m_spRes != NULL)
{
return m_spRes->GetName();
}
return NULL;
}
void KEventPointSeq::SetRes( K3DResEventPoint *res )
{
assert(m_spRes == NULL);
m_spRes = res;
if ( m_spRes != NULL)
{
m_interval = m_spRes->GetInterval();
}
}
void KEventPointSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
if( m_sIsRender )
{
realizeTime();
// m_prAxisWire01.Clear();
m_prAxisWire02.Clear();
K3DMatrix matResult;
K3DMatrixIdentity( matResult );
if ( m_pMatAttach != NULL && m_pMatParent != NULL )
{
//K3DMatrix Mat1 = *m_pMatAttach;
//K3DVector vVectorX, vVectorY, vVectorZ;
//AxisCalculation( Mat1, vVectorX, vVectorY, vVectorZ );
//m_prAxisWire01.AddLine( *K3DMatrixGetPosVector( Mat1 ), vVectorX, KColor(255,0,0,255) );
//m_prAxisWire01.AddLine( *K3DMatrixGetPosVector( Mat1 ), vVectorY, KColor(0,255,0,255) );
//m_prAxisWire01.AddLine( *K3DMatrixGetPosVector( Mat1 ), vVectorZ, KColor(0,0,255,255) );
//예전 코드 ( 문제 있음 )
// K3DMatrixMultiply( matResult, *m_pMatAttach, *m_pMatParent );
// K3DMatrixMultiply( matResult, m_matPoint, matResult );
//새로운 코드
K3DMatrixMultiply( matResult, m_matPoint, *m_pMatAttach );
K3DMatrixMultiply( matResult, matResult, *m_pMatParent );
}
else if ( m_pMatParent != NULL )
{
//예전 코드
K3DMatrixMultiply( matResult, matResult, *m_pMatParent );
//새로운 코드
// K3DMatrixMultiply( matResult, m_matPoint, *m_pMatParent );
}
else
{
matResult = m_matPoint;
}
K3DMatrix Mat1 = matResult;
K3DVector vVectorX, vVectorY, vVectorZ;
AxisCalculation( Mat1, vVectorX, vVectorY, vVectorZ, 2.f );
m_prAxisWire02.AddLine( Mat1.GetPosVector(), vVectorX, KColor(255,0,0,255) );
m_prAxisWire02.AddLine( Mat1.GetPosVector(), vVectorY, KColor(0,255,0,255) );
m_prAxisWire02.AddLine( Mat1.GetPosVector(), vVectorZ, KColor(0,0,255,255) );
m_bCube.SetTransform( matResult );
m_bCube.Render( viewport );
// viewport->RegisterWire( &m_prAxisWire01 );
viewport->RegisterWire( &m_prAxisWire02 );
}
}
const K3DMatrix &KEventPointSeq::GetPoint()
{
realizeTime();
return m_matPoint;
}
void *KEventPointSeq::Perform( KID id, KArg& msg )
{
_CID( REQ_EVPOINT );
if ( id == id_REQ_EVPOINT )
{
KMsgREQ_EVPOINT *reqmsg = static_cast<KMsgREQ_EVPOINT*>(&msg);
reqmsg->AddPoint( this );
return (void*)1;
}
return NULL;
}
void KEventPointSeq::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime ) return;
m_dwRealizedTime = m_dwTime;
if ( m_spRes != NULL )
{
K3DMatrixIdentity( m_matPoint );
m_spRes->GetData( m_dwTime, &m_matPoint );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KFXSeq::GetUVAniRect( int nCurFrame, int nFrameCount )
{
int width = int(1.f/m_fTRight);
//int height = int(1.f/m_fTBottom);
assert( nFrameCount );
int txtpos = nCurFrame%nFrameCount;
int px = txtpos%width;
int py = txtpos/width;
m_fLeft+=m_fTRight*px;
m_fRight+=m_fTRight*px;
m_fTop+=m_fTBottom*py;
m_fBottom+=m_fTBottom*py;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXBillboardSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool KFXBillboardSeq::m_sVisbleCube = false;
KFXBillboardSeq::KFXBillboardSeq()
{
m_nType = KFXTYPE_BILLBOARD;
}
KFXBillboardSeq::~KFXBillboardSeq()
{
}
KSeqObject *KFXBillboardSeq::Clone()
{
KFXBillboardSeq *obj = new KFXBillboardSeq;
obj->SetRes( m_spRes );
const K3DVertex* pVtx = m_boundCube.GetOriginVertices();
obj->SetCube( pVtx[0].x, pVtx[7].x, pVtx[0].y, pVtx[7].y, pVtx[0].z, pVtx[7].z );
return obj;
}
void KFXBillboardSeq::SetRes( KResFXBillboard *res )
{
assert(m_spRes == NULL);
m_spRes = res;
if(m_spRes != NULL)
{
m_interval = m_spRes->GetInterval();
m_prBillboard.SetBillboardRes( m_spRes );
m_prBillboard.SetTransparent( true );
m_prBillboard.SetFixedAxis( m_spRes->GetFixedAxis() );
if( m_spRes->GetAdditiveRenderMode() )
m_prBillboard.SetBlendMode( K3DMaterial::MBM_ADDTIVE_BILLBOARD );
else
m_prBillboard.SetBlendMode( K3DMaterial::MBM_BILLBOARD );
}
}
void KFXBillboardSeq::SetCube( float minx, float maxx, float miny, float maxy, float minz, float maxz )
{
m_boundCube = K3DBoundRotCube( minx, maxx, miny, maxy, minz, maxz );
}
void KFXBillboardSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
realizeTime();
if( !m_bRenderFlag ) return;
if( m_fVisResult <= 0.f )
return; //투명한 놈이므로 안 그림
if ( m_spRes != NULL )
{
m_prBillboard.SetColor( KColor( 255, 255, 255, unsigned char(255.f * (m_fVisResult * m_fMasterVisibility)) ) );
if ( m_spRes->GetUVAnimation() )
{
int nMaxFrame = m_spRes->GetUVAniMaxFrame();
float fUVRatio = 1.0f / sqrtf( (float)nMaxFrame );
assert( nMaxFrame );
int nLoopFrame = m_spRes->GetUvLoopFrame();
if( nLoopFrame == 0 )
nLoopFrame = m_spRes->GetRangeEnd();
int nAniCount = int(( nMaxFrame / ( float ) nLoopFrame ) * m_dwTime);
if ( nAniCount >= nMaxFrame )
nAniCount %= nMaxFrame;
int width = int(1.f / fUVRatio);
int txtpos = nAniCount % nMaxFrame;
int px = txtpos % width;
int py = txtpos / width;
float l, r, t, b;
l = fUVRatio * px;
r = fUVRatio + fUVRatio * px;
t = fUVRatio * py;
b = fUVRatio + fUVRatio * py;
m_prBillboard.SetUV( l, t, r, b );
}
else
{
m_prBillboard.SetUV( .0f, .0f, 1.0f, 1.0f );
}
K3DMatrix mat = m_matTransform;
K3DMatrix matResult;
if ( m_pMatAttach != NULL && m_pMatParent != NULL )
{
K3DMatrix matTemp;
K3DMatrixMultiply( matTemp, *m_pMatAttach, *m_pMatParent );
K3DMatrixMultiply( matResult, mat, matTemp );
}
else if ( m_pMatParent != NULL )
K3DMatrixMultiply( matResult, mat, *m_pMatParent );
else
matResult = mat;
m_boundCube.SetTransform( matResult );
const K3DVector *cube = m_boundCube.GetVertices();
K3DVector vCenterPos = K3DVector(0.f, 0.f, 0.f);
vCenterPos = cube[0] + (0.5f*(cube[7] - cube[0]));
m_prBillboard.SetRootMat( &matResult );
m_prBillboard.SetCenterPosition( vCenterPos );
m_prBillboard.SetTransform( matResult );
m_prBillboard.SetAngle( 2.0f * K3D_PI * m_spRes->GetRotateSpeed() * ( float ) m_dwTime / 9600.0f );
if( flag == KRenderObject::RENDEREFX_AFTER_SPRITE )
viewport->Register( &m_prBillboard, flag );
else
viewport->Register( &m_prBillboard, KRenderObject::RENDEREFX_NONE );
if( m_sVisbleCube )
{
m_boundCube.Render( viewport );
m_prCenterWire.Clear();
K3DVector vVectorX, vVectorY, vVectorZ;
vVectorX = vCenterPos;
vVectorY = vCenterPos;
vVectorZ = vCenterPos;
vVectorX.x += 3.f;
vVectorY.y += 3.f;
vVectorZ.z += 3.f;
//CenterPos
m_prCenterWire.AddLine( vCenterPos, vVectorX, KColor(255,0,0,255) );
m_prCenterWire.AddLine( vCenterPos, vVectorY, KColor(0,255,0,255) );
m_prCenterWire.AddLine( vCenterPos, vVectorZ, KColor(0,0,255,255) );
viewport->RegisterWire( &m_prCenterWire );
}
}
}
void *KFXBillboardSeq::Perform( KID id, KArg& msg )
{
_CID( SETFORCERENDER_FLAG );
_CID( SETRENDER_FLAG );
_CID( GETMESH_ANIINFO );
if( id == id_SETFORCERENDER_FLAG)
{
m_bRenderFlag = FALSE;
}
else if( id == id_SETRENDER_FLAG )
{
KMsgSET_RENDERFLAG * renderflagmsg = static_cast<KMsgSET_RENDERFLAG*>(&msg);
m_bRenderFlag = renderflagmsg->bRenderFlag;
}
else if( id == id_GETMESH_ANIINFO )
{
KMsgGET_MESHANI_INFO * meshani_info = static_cast<KMsgGET_MESHANI_INFO*>(&msg);
if( m_spRes != NULL )
{
{
if( meshani_info->nStart < m_spRes->GetInterval().GetStart() )
meshani_info->nStart = m_spRes->GetInterval().GetStart();
if( meshani_info->nEnd < m_spRes->GetInterval().GetEnd() )
meshani_info->nEnd = m_spRes->GetInterval().GetEnd();
}
}
}
return (void*)1;
}
void KFXBillboardSeq::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime ) return;
m_dwRealizedTime = m_dwTime;
if ( m_spRes != NULL )
{
m_spRes->GetData( m_dwTime, &m_fVisResult, &m_matTransform );
}
if ( m_dwTime > unsigned int(m_spRes->GetRangeEnd() + 160) )
m_fVisResult = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXParticleObject Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class KFXParticleObject
{
public:
KFXParticleObject() { m_nLifeTime = 0; m_nCurTime = 0; m_bNewParticle = false; }
virtual ~KFXParticleObject() {}
virtual void Init( const K3DMatrix *pMatParent, KResFXParticle *res, float fRadius, int nLifeTime, int nCreateTime, const K3DVector &startpos, const K3DVector &vec, const K3DVector &velocity )
{
// m_pMatParent = pMatParent;
m_pRes = res;
m_fRadius = fRadius;
m_nLifeTime = nLifeTime;
m_nCreateTime = nCreateTime;
m_nCurTime = 0;
m_vecStart = startpos;
m_vecVector = vec;
m_vecVelocity = velocity;
m_fTop = m_fLeft = 0.f;
m_fBottom = m_fRight = 1.0f;
if ( m_pRes->GetUVAnimation() )
{
m_fUVRatio = 1.0f / sqrtf( (float)m_pRes->GetUVAniMaxFrame() );
}
m_bNewParticle = true;
}
void ChangeVector( const K3DVector &vec, const K3DVector &vel )
{
m_vecVector = vec;
m_vecVelocity = vel;
}
void Process( int time )
{
m_nCurTime = abs(time - m_nCreateTime);
_ProcessParticlePos();
_ProcessUVAnimation();
_ProcessTransformVisibility();
}
const K3DVector &GetPos()
{
return m_vecPos;
}
const KColor &GetColor()
{
return m_colParticle;
}
float GetWidth()
{
return m_fWidth;
}
float GetHeight()
{
return m_fHeight;
}
bool IsLife()
{
return m_nLifeTime > m_nCurTime;
}
int GetLife()
{
return m_nLifeTime - m_nCurTime;
}
void GetUV( float *_left, float *_top, float *_right, float *_bottom )
{
*_left = m_fLeft; *_top = m_fTop; *_right = m_fRight; *_bottom = m_fBottom;
}
bool IsNewParticle() { return m_bNewParticle; }
void UsedParticle() { m_bNewParticle = false; }
protected:
virtual void _ProcessParticlePos()
{
float nTime = m_nCurTime / 160.f;
m_vecPos.x = ( m_vecVector.x * powf( m_vecVelocity.x, nTime )) * nTime;
m_vecPos.y = ( m_vecVector.y * powf( m_vecVelocity.y, nTime )) * nTime;
m_vecPos.z = ( m_vecVector.z * powf( m_vecVelocity.z, nTime )) * nTime;
K3DVector NorVec;
NorVec = m_vecVector;
Normalize( NorVec );
m_vecOldPos = m_vecPos;
m_vecPos += m_fRadius * NorVec;
m_vecPos += m_vecStart;
}
void _ProcessUVAnimation()
{
if ( m_pRes && m_pRes->GetUVAnimation() )
{
int nMaxFrame = m_pRes->GetUVAniMaxFrame();
assert( nMaxFrame );
int nLoopFrame = m_pRes->GetUvLoopFrame();
if( nLoopFrame == 0 )
nLoopFrame = m_nLifeTime;
int nAniCount = int(( nMaxFrame / ( float ) m_nLifeTime ) * m_nCurTime);
if ( nAniCount >= nMaxFrame )
nAniCount %= nMaxFrame;
int width = int(1.f / m_fUVRatio);
int txtpos = nAniCount % nMaxFrame;
int px = txtpos % width;
int py = txtpos / width;
m_fLeft = m_fUVRatio * px;
m_fRight = m_fLeft + m_fUVRatio;
m_fTop = m_fUVRatio * py;
m_fBottom = m_fTop + m_fUVRatio;
}
else if( !m_pRes )
{
_oprint( "_ProcessUVAnimation() m_pRes == NULL\n" );
}
}
void _ProcessTransformVisibility()
{
K3DMatrix matTransform;
float vis;
int dattime = int((float)((float)m_nCurTime/m_nLifeTime) * m_pRes->GetInterval().GetLength());
m_pRes->GetData( dattime, &vis, &matTransform );
m_colParticle = KColor( 255, 255, 255, unsigned char(vis * 255 ));
// Process Matrix Transfom
/* if ( m_pMatParent )
K3DMatrixMultiply( &matTransform, &mat, m_pMatParent );
else matTransform = mat;*/
// calc radius
const K3DVertex *pV = m_pRes->GetVertices();
K3DVector transVtx[4];
int i;
for( i=0 ; i < 4 ; ++i )
{
K3DVectorTransform( transVtx[i], pV[i], matTransform );
}
//K3DVector vWidth = transVtx[0] - transVtx[1];
//K3DVector vHeight = transVtx[1] - transVtx[3];
//m_fWidth = K3DVectorLength( vWidth );
m_fWidth = min( K3DVectorLength( transVtx[1] - transVtx[3] ), K3DVectorLength( transVtx[1]- transVtx[2]) ); // dirty workaround by Tyburn -_-;
//m_fHeight = K3DVectorLength( vHeight );
m_fHeight = K3DVectorLength( transVtx[0] - transVtx[1] );
}
const K3DMatrix* m_pMatParent;
// Particle Object는 실시간에 몇천개씩 생겼다 사라지므로 일부러 Smart Pointer 사용안함
// Parent에 묶여있는 상태이므로 안전성은 보장된다.
KResFXParticle* m_pRes;
float m_fUVRatio;
float m_fLeft, m_fRight, m_fTop, m_fBottom;
float m_fRadius;
KColor m_colParticle;
float m_fWidth,m_fHeight;
int m_nLifeTime;
int m_nCurTime;
int m_nCreateTime;
K3DVector m_vecPos;
K3DVector m_vecOldPos;
K3DVector m_vecStart;
K3DVector m_vecVector;
K3DVector m_vecVelocity;
bool m_bNewParticle;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXGravityParticleObject Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class KFXGravityParticleObject : public KFXParticleObject
{
public:
KFXGravityParticleObject() { m_fGravityAccel = 9.8f; m_vecGravity = K3DVector(0,0,-1); }
virtual ~KFXGravityParticleObject() {}
virtual void Init( const K3DMatrix *pMatParent, KResFXParticle *res, float fRadius, int nLifeTime, int nCreateTime, const K3DVector &startpos, const K3DVector &vec, const K3DVector &velocity )
{
KFXParticleObject::Init(pMatParent,res,false,nLifeTime,nCreateTime,startpos,vec,velocity);
m_fGravityAccel = res->GetGravityAccel();
m_vecGravity = res->GetGravity();
}
protected:
virtual void _ProcessParticlePos()
{
float nTime = m_nCurTime / 160.f;
K3DVector temp;
temp = m_vecGravity;
Normalize(temp);
temp *= m_fGravityAccel;
m_vecPos.x = float( m_vecVector.x * nTime + 0.5 * temp.x * pow(nTime, 2) );
m_vecPos.y = float( m_vecVector.y * nTime + 0.5 * temp.y * pow(nTime, 2) );
m_vecPos.z = float( m_vecVector.z * nTime + 0.5 * temp.z * pow(nTime, 2) );
K3DVector NorVec;
NorVec = m_vecVector;
Normalize( NorVec );
m_vecOldPos = m_vecPos;
m_vecPos += m_fRadius * NorVec;
m_vecPos += m_vecStart;
}
float m_fGravityAccel;
K3DVector m_vecGravity;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXReverseParticleObject Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class KFXReverseParticleObject : public KFXParticleObject
{
public:
KFXReverseParticleObject(){}
virtual ~KFXReverseParticleObject() {}
protected:
virtual void _ProcessParticlePos()
{
int tempTime = m_nCurTime;
tempTime = m_nLifeTime - tempTime;
float nTime = tempTime / 160.f;
m_vecPos.x = ( m_vecVector.x * powf( m_vecVelocity.x, nTime )) * nTime;
m_vecPos.y = ( m_vecVector.y * powf( m_vecVelocity.y, nTime )) * nTime;
m_vecPos.z = ( m_vecVector.z * powf( m_vecVelocity.z, nTime )) * nTime;
K3DVector NorVec;
NorVec = m_vecVector;
Normalize( NorVec );
m_vecOldPos = m_vecPos;
m_vecPos += m_fRadius * NorVec;
m_vecPos += m_vecStart;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXParticleSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KFXParticleSeq::KFXParticleSeq(DWORD dwParticleType)
{
m_nType = KFXTYPE_PARTICLE;
m_dwParticleType = dwParticleType;
m_bInited = false;
m_ppParticles = NULL;
m_nParticleCount = 0;
m_pMatAttach = NULL;
m_pMatParent = NULL;
}
KFXParticleSeq::~KFXParticleSeq()
{
_ClearObject();
}
KSeqObject *KFXParticleSeq::Clone()
{
KFXParticleSeq *obj = new KFXParticleSeq(m_dwParticleType);
obj->SetRes( m_spRes );
return obj;
}
void KFXParticleSeq::SetRes( KResFXParticle *res )
{
assert(m_spRes == NULL);
m_spRes = res;
if(m_spRes != NULL)
{
m_interval = m_spRes->GetInterval();
m_prParticle.SetParticleRes( m_spRes );
m_prParticle.SetTransparent( true );
if( m_spRes->GetAdditiveRenderMode() )
m_prParticle.SetBlendMode( K3DMaterial::MBM_ADDTIVE_BILLBOARD );
else
m_prParticle.SetBlendMode( K3DMaterial::MBM_BILLBOARD );
m_prParticle.SetAttachParent( m_spRes->IsAttachParent() );
}
}
void KFXParticleSeq::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
realizeTime();
if( !m_bRenderFlag ) return;
static KFXParticlePrimitive::_PARTICLE particle;
if ( m_ppParticles )
{
m_prParticle.ResetParticleCount();
int nDrawCount = 0;
for( int i = 0 ; i < m_nParticleCount ; ++i )
{
KFXParticleObject *ptc = m_ppParticles[i];
if( ptc->IsLife() == true )
{
ptc->Process( m_dwMyTime );
particle.pos = ptc->GetPos();
particle.color = ptc->GetColor();
particle.fWidth = ptc->GetWidth();
particle.fHeight = ptc->GetHeight();
ptc->GetUV( &particle.l, &particle.t, &particle.r, &particle.b );
m_prParticle.SetParticleInfo( nDrawCount, particle );
if( ptc->IsNewParticle() )
{
m_prParticle.NewParticle( nDrawCount );
ptc->UsedParticle();
}
++nDrawCount;
}
}
if( flag == KRenderObject::RENDEREFX_AFTER_SPRITE )
viewport->Register( &m_prParticle, flag );
else
viewport->Register( &m_prParticle, KRenderObject::RENDEREFX_NONE );
}
}
void *KFXParticleSeq::Perform( KID id, KArg& msg )
{
_CID( SETFORCERENDER_FLAG );
_CID( GETMESH_ANIINFO );
if( id == id_SETFORCERENDER_FLAG)
{
m_bRenderFlag = FALSE;
}
else if( id == id_GETMESH_ANIINFO )
{
KMsgGET_MESHANI_INFO * meshani_info = static_cast<KMsgGET_MESHANI_INFO*>(&msg);
if( m_spRes != NULL )
{
// if( _stricmp( meshani_info->strFindName.c_str(), m_pResMesh->GetName() ) == 0 )
{
if( meshani_info->nStart < m_spRes->GetInterval().GetStart() )
meshani_info->nStart = m_spRes->GetInterval().GetStart();
if( meshani_info->nEnd < m_spRes->GetInterval().GetEnd() )
meshani_info->nEnd = m_spRes->GetInterval().GetEnd();
}
}
}
return (void*)1;
}
void KFXParticleSeq::realizeTime()
{
if(m_spRes == NULL)
return;
if ( m_bInited == false )
{
_Initialize();
m_dwOldTime = m_dwTime;
m_dwOldCreateTime = m_spRes->GetRangeStart();
m_dwMyTime = 0;
}
int nInterval = m_dwTime - m_dwOldTime;
if ( nInterval < 0 )
{
nInterval = m_interval.GetEnd() - m_dwOldTime + m_dwTime;
if ( m_spRes->IsLoop() == false )
{
_ClearObject();
m_bInited = false;
return;
}
}
m_dwMyTime += nInterval;
if( (int(m_dwMyTime) - int(m_dwOldCreateTime)) >= m_spRes->GetCreateTime() )
{
if ( (unsigned int)m_spRes->GetRangeStart() <= m_dwMyTime && (( m_spRes->IsLoop() == true )
|| ( m_spRes->IsLoop() == false && (unsigned int)m_spRes->GetRangeEnd() > m_dwMyTime )) )
{
int count = (m_dwMyTime - m_dwOldCreateTime) / m_spRes->GetCreateTime();
//gmpbigsun( 20131125 ) : 아래코드는 파티클 생성시간을 같도록 강제로 만들어버린것이다
//의도를 알수없으나, 상당히 잘못된 코드임. 주석처리된것으로 바꾸면 랜덤생성인것임.
//파티클 수정
//2009-21-26 : hunee
//m_dwOldCreateTime = m_dwMyTime - ((m_dwMyTime-m_dwOldCreateTime) % m_spRes->GetCreateTime());
m_dwOldCreateTime = m_dwMyTime - (m_dwMyTime - m_dwOldCreateTime);
for( int i = 0 ; i < m_nParticleCount ; ++i )
{
KFXParticleObject *ptc = m_ppParticles[i];
if( ptc->IsLife() == false )
{
_CreateParticle( i , m_spRes->GetCreateTime() );
if ( (--count) == 0 ) break;
}
}
}
}
m_dwOldTime = m_dwTime;
K3DMatrix matResult;
K3DMatrixIdentity( matResult );
if ( m_pMatAttach != NULL && m_pMatParent != NULL )
{
K3DMatrix matTemp;
K3DMatrixMultiply( matTemp, *m_pMatAttach, *m_pMatParent );
K3DMatrixMultiply( matResult, matResult, matTemp );
}
else if ( m_pMatParent != NULL )
K3DMatrixMultiply( matResult, matResult, *m_pMatParent );
m_prParticle.SetRootMat( &matResult );
m_prParticle.SetCenterPosition( K3DVector( matResult._41, matResult._42, matResult._43 ) );
}
/// Get random vector (vertex) from given direction vector and angle.
static inline K3DVector K3DVectorGetRandom( const K3DVector &vec, float fAngle )
{
K3DVector Result, Sample;
float fRadius, fTheta, fPitch;
float fNewRadius, fNewTheta, fNewPitch;
Sample = K3DVector( 0, 0, 1 );
fRadius = sqrtf( ( Sample.x * Sample.x ) + ( Sample.y * Sample.y ) + ( Sample.z * Sample.z ) );
fPitch = acosf( Sample.z / fRadius );
if( Sample.x == 0.000000f ) fTheta = 90 * K3D_PI / 180.f;
else fTheta = ( Sample.x > 0.f ) ? atanf( Sample.y / Sample.x ) : atanf( Sample.y / Sample.x ) + K3D_PI;
int nUnit = int( fAngle * 10.f );
float fRandPitch = fAngle - ( 0.1f * ( rand()%(nUnit * 2) ) );
// float fRandTheta = fAngle - ( 0.1f * ( rand()%(nUnit * 2) ) );
float fRandTheta = 180 - ( 1.0f * ( rand()%(180*2) ) );
fRandPitch = fRandPitch * K3D_PI / 180.f;
fRandTheta = fRandTheta * K3D_PI / 180.f;
fNewRadius = fRadius;
fNewPitch = fPitch + fRandPitch;
// fNewTheta = fTheta + fRandTheta;
fNewTheta = fRandTheta;
Result.x = fNewRadius * cosf( fNewTheta ) * sinf( fNewPitch );
Result.y = fNewRadius * sinf( fNewTheta ) * sinf( fNewPitch );
Result.z = fNewRadius * cosf( fNewPitch );
Normalize( Result );
///////////////////////////////////////
///////////////////////////////////////
K3DVector va;
K3DMatrix mat;
float fDot = K3DVectorDot( Sample, vec );
float ffAngle = acosf( fDot );
K3DVectorCross( va, Sample, vec );
K3DMatrixRotationAxis( mat, va, ffAngle );
K3DVector Res;
K3DVectorTransform( Res, Result, mat );
return Res;
}
void KFXParticleSeq::_CreateParticle( int index, int TimeUnit )
{
if( index < 0 || index >= m_nParticleCount ) return;
/* K3DMatrix mat;
m_spRes->GetData( m_dwTime, &m_fVisResult, &mat );
if ( m_pMatParent )
K3DMatrixMultiply( &m_matTransform, &mat, m_pMatParent );
else
m_matTransform = mat;*/
m_spRes->GetData( m_dwTime, &m_fVisResult, &m_matTransform );
// calc radius
const K3DVertex *pV = m_spRes->GetVertices();
K3DVector transVtx[4];
int i;
for( i=0 ; i < 4 ; ++i )
{
K3DVectorTransform( transVtx[i], pV[i], m_matTransform );
}
K3DVector vRadius = transVtx[0] - transVtx[1];
m_fRadius = K3DVectorLength( vRadius );
//K3DMatrixGetZVector( m_vecVector, m_matTransform );
K3DVectorTransformNormal( m_vecVector, m_spRes->GetNormal(), m_matTransform );
Normalize( m_vecVector );
m_vecVelocity = m_spRes->GetVelocity();
KFXParticleObject *ptc = m_ppParticles[index];
K3DVector pos;
K3DMatrixGetPosVector( pos, m_matTransform );
K3DVector vVec = K3DVectorGetRandom( m_vecVector, m_spRes->GetSpreadAngle() );
K3DVector vBeginSpeed = m_spRes->GetBeginSpeed();
vVec *= _GetRandom( vBeginSpeed.x, vBeginSpeed.y );
int nLifeTime = m_spRes->GetLifeTime() + (rand() % (m_spRes->GetLifeTimeVariation() - m_spRes->GetLifeTime()));
ptc->Init( m_pMatParent, m_spRes, m_fRadius, nLifeTime, m_dwMyTime, pos, vVec, m_vecVelocity );
}
void KFXParticleSeq::_Initialize()
{
_ClearObject();
if ( m_spRes )
{
m_nParticleCount = (m_spRes->GetLifeTime() + m_spRes->GetLifeTimeVariation()) / m_spRes->GetCreateTime();
m_prParticle.SetParticleCount( m_nParticleCount );
_GenerateObject();
m_bInited = true;
}
}
float KFXParticleSeq::_GetRandom( float min, float variation )
{
float Result;
if( variation == 0.f ) return min;
Result = min + ( rand() % (int)(variation) );
return Result;
}
void KFXParticleSeq::_GenerateObject()
{
assert( m_nParticleCount && "Particle Zero Count" );
if( !m_nParticleCount ) return;
switch(m_dwParticleType)
{
case KPARTICLE_DEFAULT:
{
m_ppParticles = new KFXParticleObject*[m_nParticleCount];
for(int i = 0; i < m_nParticleCount; ++i)
{
m_ppParticles[i] = new KFXParticleObject;
}
break;
}
case KPARTICLE_GRAVITY:
{
m_ppParticles = reinterpret_cast<KFXParticleObject **>( new KFXGravityParticleObject*[m_nParticleCount] );
for(int i = 0; i < m_nParticleCount; ++i)
{
m_ppParticles[i] = new KFXGravityParticleObject;
}
break;
}
case KPARTICLE_REVERSE:
{
m_ppParticles = reinterpret_cast<KFXParticleObject **>( new KFXReverseParticleObject*[m_nParticleCount] );
for(int i = 0; i < m_nParticleCount; ++i)
{
m_ppParticles[i] = new KFXReverseParticleObject;
}
break;
}
default:
{
assert(false && "Invalid Particle Type");
}
}
}
void KFXParticleSeq::_ClearObject()
{
if ( m_ppParticles )
{
for(int i = 0 ; i < m_nParticleCount; ++i)
SAFE_DELETE(m_ppParticles[i]);
SAFE_DELETE_ARRAY(m_ppParticles);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXAferImagerSeq Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
const int FRAME_PER_VTX = 1;
const int SPLINE_ARGUMENT = 4;
}
KFXAfterImageSeq::KFXAfterImageSeq()
{
m_bOldValidate = false;
m_pMatLerp = NULL;
m_dwVertexCount = 0;
m_dwLastSplinePushCount = 0;
m_dwLastNormalLineCount = 0;
m_pVertexListOne = m_pVertexListTwo = NULL;
K3DMatrixIdentity( m_matOld );
K3DMatrixIdentity( m_matRoot );
K3DMatrixIdentity( m_matLocal );
}
KFXAfterImageSeq::~KFXAfterImageSeq()
{
SAFE_DELETE_ARRAY(m_pMatLerp);
SAFE_DELETE_ARRAY(m_pVertexListOne);
SAFE_DELETE_ARRAY(m_pVertexListTwo);
}
KSeqObject *KFXAfterImageSeq::Clone()
{
KFXAfterImageSeq *obj = new KFXAfterImageSeq;
obj->SetRes( m_spRes );
return obj;
}
void KFXAfterImageSeq::SetRes( KResFXAfterImage *pRes )
{
assert(m_spRes == NULL);
m_spRes = pRes;
if(m_spRes != NULL)
{
m_interval = m_spRes->GetInterval();
// 한 Frame당 4개씩 Spline 보간
m_prAfterImage.Initialize(m_spRes->GetFrameNumber() * FRAME_PER_VTX );
m_prAfterImage.SetTexture(m_spRes->GetTexture());
m_pMatLerp = new K3DMatrix[ max( m_spRes->GetFrameNumber(), FRAME_PER_VTX ) ];
// Catmull-rom Spline을 위한 Vertex
m_pVertexListOne = new K3DVertex[m_spRes->GetFrameNumber()];
m_pVertexListTwo = new K3DVertex[m_spRes->GetFrameNumber()];
m_prAfterImage.SetBlendMode( m_spRes->GetBlendMode() );
}
}
void KFXAfterImageSeq::Render( KViewportObject *pViewport, DWORD flag, const K3DMatrix * pAttachMat )
{
realizeTime();
float vis = m_fMasterVisibility * m_fVisResult;
if( vis <= 0.f )
return;
if ( m_pMatAttach != NULL && m_pMatParent != NULL )
{
m_matRoot = *m_pMatParent;
m_matLocal = *m_pMatAttach;
K3DMatrix matResult;
K3DMatrixMultiply( matResult, *m_pMatAttach, *m_pMatParent );
m_prAfterImage.SetRootMat( &matResult );
m_prAfterImage.SetCenterPosition( K3DVector( matResult._41, matResult._42, matResult._43 ) );
}
else if ( m_pMatParent != NULL )
{
m_matRoot = *m_pMatParent;
m_prAfterImage.SetRootMat( &m_matRoot );
m_prAfterImage.SetCenterPosition( K3DVector( m_matRoot._41, m_matRoot._42, m_matRoot._43 ) );
}
m_prAfterImage.SetVisibility( vis );
pViewport->Register(&m_prAfterImage, KRenderObject::RENDEREFX_NONE );
}
void* KFXAfterImageSeq::Perform( int id, KArg& msg)
{
_CID( AFTER_IMAGE_MOVE );
if ( id == id_AFTER_IMAGE_MOVE )
{
KMsgAfterImage_MOVE * pMoveMsg = static_cast<KMsgAfterImage_MOVE*>(&msg);
this->m_prAfterImage.SetMoveAdded(pMoveMsg->GetMoveAdded() );
K3DVertex vPos;
K3DMatrixGetPosVector(vPos, m_matOld);
vPos+= pMoveMsg->GetMoveAdded();
m_matOld.SetPosVector(vPos);
}
return NULL;
}
void KFXAfterImageSeq::realizeTime()
{
// realize 할 필요 없음 (이미 했으므로)
if ( m_dwRealizedTime == m_dwTime )
return;
if( m_spRes == NULL)
return;
// Old Matrix값의 초기화
if( m_bOldValidate == false )
{
m_bOldValidate = true;
return;
}
int nInterval = static_cast<int>(m_dwTime - m_dwRealizedTime);
if(nInterval < 0)
nInterval += m_interval.GetLength();
// 추가될 Spline Frame의 갯수
int dwAddFrames = min( nInterval / m_spRes->GetFrameTime(), m_spRes->GetFrameNumber() );
if( dwAddFrames == 0)
{
_PushNormalLine( nInterval );
return;
}
//// Spline을 만들수 없을때는 리턴
//if( m_dwVertexCount + dwAddFrames < SPLINE_ARGUMENT)
// return;
_MakeLerpMatrix(dwAddFrames, nInterval);
// 새로운 vertex를 얻어서 저장. (시간이 늦은 vertex부터 추가하자)
K3DSPRITEVERTEX vtx0, vtx1;
for(int i = dwAddFrames - 1; i >= 0; --i)
{
int nTime = static_cast<int>( m_dwTime - (i * m_spRes->GetFrameTime()) );
// 시간이 한번 loop 를 돈 경우
if(nTime < 0)
nTime += m_interval.GetLength();
m_spRes->GetData(nTime, vtx0, vtx1, m_pMatLerp[i], m_fVisResult);
DWORD dwIndex = m_dwVertexCount % (m_spRes->GetFrameNumber());
m_pVertexListOne[dwIndex] = vtx0.pos;
m_pVertexListTwo[dwIndex] = vtx1.pos;
m_dwVertexCount++;
}
// Spline을 만들수 없을때는 리턴
if( m_dwVertexCount + dwAddFrames < SPLINE_ARGUMENT)
return;
// Spline 생성
_PushSpline( dwAddFrames);
// 새로운 vertex가 추가 되었던 시간을 기록한다.
m_dwRealizedTime = m_dwTime;
}
void KFXAfterImageSeq::_MakeLerpMatrix(DWORD dwAddFrames, int nInterval)
{
// i 가 작은 값이 current time 가깝고, i 가 커질수록 old time에 근접한다.
for(unsigned int i = 0; i < dwAddFrames; ++i)
{
K3DMatrixIdentity(m_pMatLerp[i]);
DWORD dwDiff = abs( nInterval - (int)i * m_spRes->GetFrameTime() );
float fWeight = static_cast<float>(dwDiff)/ static_cast<float>( nInterval );
// 예전에 이동했던 값과 비교해서 matrix 보간
if ( m_pMatParent != NULL )
K3DMatrixLerp(m_pMatLerp[i], m_matOld, m_matOld, fWeight);
}
}
void KFXAfterImageSeq::_PushNormalLine(int nInterval)
{
// 추가될 Spline Frame의 갯수
DWORD dwFrameTime = m_spRes->GetFrameTime() / FRAME_PER_VTX;
if(dwFrameTime <= 0)
return;
DWORD dwAddFrames = min( (DWORD)nInterval / dwFrameTime, (DWORD)FRAME_PER_VTX );
if( dwAddFrames == 0)
return;
m_prAfterImage.PopVertex( m_dwLastNormalLineCount);
m_dwLastNormalLineCount = dwAddFrames;
_MakeLerpMatrix(dwAddFrames, nInterval);
m_prAfterImage.ReserveVtx( dwAddFrames );
K3DSPRITEVERTEX vtx0, vtx1;
for(int i = dwAddFrames - 1; i >= 0; --i)
{
int nTime = static_cast<int>( m_dwTime - (i * dwFrameTime) );
// 시간이 한번 loop 를 돈 경우
if(nTime < 0)
nTime += m_interval.GetLength();
m_spRes->GetData(nTime, vtx0, vtx1, m_pMatLerp[i], m_fVisResult);
m_prAfterImage.PushVertex( vtx0, vtx1);
}
m_prAfterImage.UpdateVertex();
}
void KFXAfterImageSeq::_PushSpline(DWORD dwAddFrames)
{
m_prAfterImage.PopVertex( m_dwLastSplinePushCount + m_dwLastNormalLineCount);
m_dwLastSplinePushCount = 0;
m_dwLastNormalLineCount = 0;
DWORD dwMaxFrameNumber = m_spRes->GetFrameNumber();
DWORD dwOldVertexCount = m_dwVertexCount - dwAddFrames;
const float fScaleLargeUnit = 1.f / (float)FRAME_PER_VTX;
DWORD dwOffset = 0;
if( dwMaxFrameNumber < dwAddFrames + SPLINE_ARGUMENT)
dwOffset = SPLINE_ARGUMENT -1 - dwMaxFrameNumber + dwAddFrames;
// 예전에 저장된 Frame의 Vertex count가 Spline Argument를 만족하지 못함.
if( dwOldVertexCount < SPLINE_ARGUMENT)
dwOffset = SPLINE_ARGUMENT -1 - dwOldVertexCount;
//dwAddFrames -= dwOffset;
if( dwAddFrames >= dwOffset )
dwAddFrames -= dwOffset;
else
return;
DWORD dwIndexList[SPLINE_ARGUMENT];
// 더해지는 Frame 만큼 Spline 생성
K3DSPRITEVERTEX vtx0, vtx1;
m_dwLastSplinePushCount = FRAME_PER_VTX + 1;
m_prAfterImage.ReserveVtx( dwAddFrames * FRAME_PER_VTX + m_dwLastSplinePushCount );
for(unsigned int i = 0; i < dwAddFrames; ++i)
{
// 가장 최근 Frame은 Index 값이 낮음.
for(DWORD m = 0; m < SPLINE_ARGUMENT; ++m)
dwIndexList[m] = (dwOldVertexCount + i + dwOffset - m) % dwMaxFrameNumber;
// Frame 별로 넣어주자.
for(DWORD k = 0; k < FRAME_PER_VTX; ++k)
{
K3DVectorCatMullRom(vtx0.pos, m_pVertexListOne[dwIndexList[3] ],
m_pVertexListOne[dwIndexList[2] ], m_pVertexListOne[dwIndexList[1] ],
m_pVertexListOne[dwIndexList[0] ], fScaleLargeUnit * k);
K3DVectorCatMullRom(vtx1.pos, m_pVertexListTwo[dwIndexList[3] ],
m_pVertexListTwo[dwIndexList[2] ], m_pVertexListTwo[dwIndexList[1] ],
m_pVertexListTwo[dwIndexList[0] ], fScaleLargeUnit * k);
m_prAfterImage.PushVertex(vtx0, vtx1);
}
}
// 마지막 연결부위 (이 부분은 넣었다 뺐다 한다)
for(DWORD m = 0; m < SPLINE_ARGUMENT; ++m)
dwIndexList[m] = (m_dwVertexCount - 1 - m) % dwMaxFrameNumber;
for(DWORD k = 0; k < m_dwLastSplinePushCount; ++k)
{
K3DVectorCatMullRom(vtx0.pos, m_pVertexListOne[dwIndexList[2] ],
m_pVertexListOne[dwIndexList[1] ], m_pVertexListOne[dwIndexList[0] ],
m_pVertexListOne[dwIndexList[0] ], fScaleLargeUnit * k);
K3DVectorCatMullRom(vtx1.pos, m_pVertexListTwo[dwIndexList[2] ],
m_pVertexListTwo[dwIndexList[1] ], m_pVertexListTwo[dwIndexList[0] ],
m_pVertexListTwo[dwIndexList[0] ], fScaleLargeUnit * k);
m_prAfterImage.PushVertex(vtx0, vtx1);
}
m_prAfterImage.UpdateVertex();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KSeqTextureRender Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KSeqTextureRender::KSeqTextureRender()
{
m_bSourceRenderFlag =true;
m_pSeqSource = NULL;
m_pRenderTarget = NULL;
m_pCamera = NULL;
m_sizeTarget = KSize( 256, 256 );
m_formatTarget = K3DFMT_A8R8G8B8;
m_pViewport = NULL;
// Default Render Freq is 60frame.
SetRenderFreq(KSEQ_RENDER_60);
m_dwTime = 0;
K3DMatrixIdentity(m_matLocal);
}
KSeqTextureRender::~KSeqTextureRender()
{
m_vtUserLight.clear();
SAFE_DELETE(m_pViewport);
SAFE_DELETE(m_pSeqSource);
}
void KSeqTextureRender::Initialize( KSeqObject *src, const KSize &targetSize, const K3DFORMAT &texformat)
{
m_sizeTarget = targetSize;
m_formatTarget = texformat;
m_pSeqSource = src;
KViewportStruct vp;
vp.Width = targetSize.cx;
vp.Height = targetSize.cy;
vp.X = vp.Y = 0;
vp.MinZ = 0;
vp.MaxZ = 1.0f;
m_pViewport = new KViewportObject(KViewportObject::VIEWPORT_GAME, true, true);
m_pViewport->Initilaize( KDeviceManager::GetDeviceManager()->GetRenderDevice(), vp, 1, 50000 );
m_pViewport->SetFillColor( K3DColor(0,0,0) );
m_pViewport->SetSceneAmbient( KColor( 250, 250, 250, 255 ) );
m_interval = m_pSeqSource->GetInterval();
KResSprite * pResSprite = new KResSprite;
//m_pRenderTarget = KDeviceManager::GetDeviceManager()->GetRenderDevice()->CreateRenderTarget( targetSize.cx, targetSize.cy, 1, m_formatTarget, true );
m_pRenderTarget = KDeviceManager::GetDeviceManager()->GetRenderDevice()->CreateRenderTarget( targetSize.cx, targetSize.cy, 1, m_formatTarget, K3DRenderTarget::DEPTH_ENABLE );
pResSprite->SetTexture(m_pRenderTarget,NULL);
m_prSprite.SetRes(pResSprite);
m_prSprite.SetTargetSize((float)m_sizeTarget.cx,(float)m_sizeTarget.cy);
}
void KSeqTextureRender::SetUserCamera( K3DCamera *pCam )
{
m_bSourceRenderFlag = true;
m_pCamera = pCam;
}
void KSeqTextureRender::AddUserLight(K3DLight * pLight)
{
m_bSourceRenderFlag = true;
m_vtUserLight.push_back(pLight);
}
void KSeqTextureRender::SetRenderFreq(DWORD dwRenderFreq)
{
switch(dwRenderFreq)
{
case KSEQ_RENDER_ALL:
m_dwRenderFrameTime = 1;
break;
case KSEQ_RENDER_60:
m_dwRenderFrameTime = 1000 / 60;
break;
case KSEQ_RENDER_30:
m_dwRenderFrameTime = 1000 / 30;
break;
case KSEQ_RENDER_ONCE:
m_dwRenderFrameTime = 0;
break;
default:
{
assert(false && "Render Freq Argument is false");
}
}
}
void KSeqTextureRender::SetAddictive(bool bUseAddictive)
{
m_prSprite.SetAdditiveRenderMode(bUseAddictive);
}
void KSeqTextureRender::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
realizeTime();
if(m_pRenderTarget == NULL)
return;
if ( m_pMatParent != NULL )
K3DMatrixMultiply( m_matResult, m_matLocal, *m_pMatParent );
else
m_matResult = m_matLocal;
m_prSprite.SetTransform( m_matResult );
m_prSprite.SetVisibility( m_fMasterVisibility );
if(!m_bSourceRenderFlag)
{
viewport->Register( &m_prSprite);
return;
}
m_pViewport->SetFillColor( KColor(0,0,0,0) );
if ( m_pCamera == NULL)
{
{ assert(false && "Must Set Camera!"); }
}
//m_pCamera->Render( m_pViewport );
m_pViewport->SetCamera(m_pCamera);
for(int i = 0; i < (int)m_vtUserLight.size(); ++i)
{
m_pViewport->AddLight(m_vtUserLight.at(i) );
}
m_pSeqSource->Render( m_pViewport );
m_pViewport->Render( m_pRenderTarget );
viewport->Register( &m_prSprite);
m_bSourceRenderFlag = false;
}
KSeqObject* KSeqTextureRender::Clone()
{
KSeqTextureRender *obj = new KSeqTextureRender;
obj->Initialize( m_pSeqSource, m_sizeTarget,m_formatTarget );
return obj;
}
void KSeqTextureRender::realizeTime()
{
if ( m_dwRealizedTime == m_dwTime || m_dwRenderFrameTime == 0 || m_dwTime - m_dwRealizedTime < m_dwRenderFrameTime )
{
return;
}
m_bSourceRenderFlag = true;
m_dwRealizedTime = m_dwTime;
if ( m_pSeqSource != NULL )
{
m_pSeqSource->SetTime( m_dwRealizedTime );
m_pSeqSource->realizeTime();
}
}