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

1512 lines
33 KiB
C++

#include "stdafx.h"
#include "KSeqPathEffect.h"
#include <mmo/ArTime.h>
#include "K3DTypes.h"
#include "TerrainMapEngine.h"
#include "KViewport.h"
CTerrainMapEngine* _KSeqPathEffect::m_pTerrainEngine = NULL;
CTerrainMapEngine* KSeqPathEffectChain::m_pTerrainEngine = NULL;
// KResEffectEmitter
// 에디터에서만 사용
KResource* KResEffectEmitter::Clone()
{
KResEffectEmitter* res = new KResEffectEmitter;
res->SetStartTime(m_dwStartTime);
res->SetLifeTime(m_nLifeTime);
res->SetStartPos(m_fStartPos);
res->SetVelocity(m_fVelocity);
res->SetDirectional(m_bDirectional);
int size = (int)m_vAniNames.size();
for(int i = 0; i < size; i++)
{
res->AddAniName(m_vAniNames[i].c_str(), m_vAniFileNames[i].c_str());
}
return res;
}
// 에디터에서만 사용
KResource* KResPathEffect::Clone()
{
KResPathEffect* res = new KResPathEffect;
int size = (int)m_vPoints.size();
for(int i = 0; i < size; i++)
{
K3DPoint p = m_vPoints[i];
res->AddPoints(&p, 1);
}
res->SetOfsZ(m_fOfsZ);
res->SetTotalPointVectorLength(m_fTotalPointVectorLength);
size = (int)m_vEmitters.size();
for(int i = 0; i < size; i++)
{
KResEffectEmitter* resEmitter = (KResEffectEmitter*) m_vEmitters[i]->Clone();
res->AddEmitter(resEmitter);
}
res->SetStartTime(m_dwStartTime);
res->SetLifeTime(m_dwLifeTime);
res->SetHasPolyLine(m_bHasPolyLine);
res->SetPolyLineWidth(m_fPolyLineWidth);
res->SetPolyLineColor(m_dwPolyLineColor);
res->SetPolyLineTexName(m_strPolyLineTexName.c_str());
return res;
}
// 다~ 지운다
void KResPathEffect::DelEmitters()
{
m_vEmitters.erase(m_vEmitters.begin(), m_vEmitters.end());
}
// 일부만 지운다
void KResPathEffect::DelEmitters(int nId, int numEmitters)
{
m_vEmitters.erase(m_vEmitters.begin() + nId, m_vEmitters.begin() + nId + numEmitters);
}
// 다~ 지운다
void KResPathEffect::DelPoints()
{
m_vPoints.erase(m_vPoints.begin(), m_vPoints.end());
m_fTotalPointVectorLength = 0.0f;
}
// 일부만 지운다
void KResPathEffect::DelPoints(int nId, int numPoint)
{
m_vPoints.erase(m_vPoints.begin() + nId, m_vPoints.begin() + nId + numPoint);
m_fTotalPointVectorLength = CalcPointVectorLength(0, m_vPoints.size() - 1);
}
void KResPathEffect::AddPoints(K3DPoint* pPoints, int numPoints)
{
int oldCap = m_vPoints.capacity();
int newCap = m_vPoints.size() + numPoints;
if(oldCap < newCap) m_vPoints.reserve(newCap);
//newCap = m_vPoints.capacity(); // 임시 코드
for(int i = 0; i < numPoints; i++)
{
m_vPoints.push_back(pPoints[i]);
// 새로 추가된 벡터의 길이를 전체 길이에 더한다
int size = (int)m_vPoints.size();
if(size >= 2)
{
float dx = m_vPoints[size - 1].x - m_vPoints[size - 2].x;
float dy = m_vPoints[size - 1].y - m_vPoints[size - 2].y;
m_fTotalPointVectorLength += sqrtf(dx * dx + dy * dy);
}
}
}
void KResPathEffect::InsertPoints(int nId, K3DPoint* pPoints, int numPoints)
{
int oldCap = (int)m_vPoints.capacity();
int newCap = (int)m_vPoints.size() + numPoints;
if(oldCap < newCap) m_vPoints.reserve(newCap);
for(int i = 0; i < numPoints; i++)
{
m_vPoints.insert(m_vPoints.begin() + nId + i, pPoints[i]);
//// 새로 추가된 벡터의 길이를 전체 길이에 더한다
//int size = m_vPoints.size();
//if(size >= 2)
//{
// float dx = m_vPoints[size - 1].x - m_vPoints[size - 2].x;
// float dy = m_vPoints[size - 1].y - m_vPoints[size - 2].y;
// m_fTotalPointVectorLength += sqrtf(dx * dx + dy * dy);
//}
m_fTotalPointVectorLength = CalcPointVectorLength(0, m_vPoints.size() - 1);
}
}
float KResPathEffect::CalcPointVectorLength(int nStart, int nEnd)
{
//m_fTotalPointVectorLength = 0.0f;
//int size = m_vPoints.size();
//if(size < 2) return;
if(nEnd >= (int) m_vPoints.size()) assert(0);
if(nStart < 0) assert(0);
if(nStart > nEnd) assert(0);
if(nStart == nEnd) return 0.0f;
float fRes = 0.0f;
for(int i = nStart; i < nEnd; i++)
{
float dx = m_vPoints[i + 1].x - m_vPoints[i].x;
float dy = m_vPoints[i + 1].y - m_vPoints[i].y;
fRes += sqrtf(dx * dx + dy * dy);
}
return fRes;
}
// 좀 느리다.. 에디터용으로만 쓰자.
int KResPathEffect::GetPoint(float fPos, K3DPoint& pRes)
{
if(fPos < 0.0f || fPos > 1.0f) return -1; // 에러
int numPoints = (int)m_vPoints.size();
int n;
if(fPos == 1.0f) // 예외 처리
{
pRes = m_vPoints[numPoints - 1];
return (numPoints - 1);
}
fPos *= m_fTotalPointVectorLength; // 절대 좌표값으로 바꾼다.
for(n = 0; n < numPoints; n++)
{
//if(m_vPoints[n].fLength > fPos) break;
if(CalcPointVectorLength(0, n) > fPos) break;
}
--n;
//float fraction = fPos - m_vVerts[n].fLength;
float fraction = fPos - CalcPointVectorLength(0, n);
K3DPoint vec = m_vPoints[n + 1] - m_vPoints[n];
float mag = sqrtf(vec.x * vec.x + vec.y * vec.y);
fraction /= mag;
pRes = m_vPoints[n] + vec * fraction;
return n;
}
//void KResPathEffect::SetStartTime()
//{
// m_dwStartTime = GetSafeTickCount();
//}
//
//DWORD KResPathEffect::GetStartTime()
//{
// return m_dwStartTime;
//}
// KResPathEffectChain
//void KResPathEffectChain::Clear()
//{
// // 리소스 릴리즈는 Seq 시리즈에서..
//
//
// //m_vPathEffects.erase(m_vPathEffects.begin(), m_vPathEffects.end());
// DelPathEffects();
//}
//
//// 다~ 지운다
//void KResPathEffectChain::DelPathEffects()
//{
// m_vPathEffects.erase(m_vPathEffects.begin(), m_vPathEffects.end());
//}
//
//// 일부만 지운다
//void KResPathEffectChain::DelPathEffects(int nId, int numPathEffects)
//{
// m_vPathEffects.erase(m_vPathEffects.begin() + nId, m_vPathEffects.begin() + nId + numPathEffects);
//}
//void KResPathEffectChain::AddPathEffect(KResPathEffect* pPathEffect)
//{
// //int oldCap = m_vPoints.capacity();
// //int newCap = m_vPoints.size() + numPoints;
// //if(oldCap < newCap) m_vPoints.reserve(newCap);
//
// m_vPathEffects.push_back(pPathEffect);
//}
// KEffectEmitter
KEffectEmitter::KEffectEmitter()
{
m_bActive = FALSE;
//m_bActive = TRUE;
m_dwCurrTime = 0xFFFFFFFF;
m_fCurrPos = 0.0f;
m_pSeqModel = NULL;
m_dwStartTime = 0;
m_nLifeTime = -1;
}
KEffectEmitter::~KEffectEmitter()
{
Clear();
}
void KEffectEmitter::Clear()
{
DelSeqModel();
}
void KEffectEmitter::DelSeqModel()
{
SAFE_DELETE(m_pSeqModel);
}
void KEffectEmitter::SetRes(KResEffectEmitter* pRes)
{
Clear();
m_spRes = pRes;
assert(m_spRes != NULL);
m_fCurrPos = m_spRes->GetStartPos();
CreateSeqModel();
m_dwStartTime = m_spRes->GetStartTime();
m_nLifeTime = m_spRes->GetLifeTime();
}
KResEffectEmitter* KEffectEmitter::GetRes()
{
return m_spRes;
}
void KEffectEmitter::CreateSeqModel()
{
DelSeqModel();
int size = m_spRes->GetNumAnis();
if(size <= 0) return;
KSeqModel* pModel = new KSeqModel;
for(int i = 0; i < size; i++)
{
const char* szAniName = m_spRes->GetAniName(i);
const char* szFileName = m_spRes->GetAniFileName(i);
if(strcmp(szAniName, PFX_NONX3) == 0) continue;
if(strcmp(szFileName, PFX_NONX3) == 0) continue;
pModel->AddAnimation(szAniName, szFileName);
}
m_pSeqModel = pModel;
}
void KEffectEmitter::Update(DWORD dwTime)
{
//dwTime -= m_dwStartTime;
//if(dwTime < m_spRes->GetStartTime()) m_dwCurrTime = 0xFFFFFFFF;
//else m_dwCurrTime = dwTime - m_spRes->GetStartTime();
if(dwTime < m_dwStartTime) m_dwCurrTime = 0xFFFFFFFF;
else m_dwCurrTime = dwTime - m_dwStartTime;
BOOL bActive;
if(m_dwCurrTime == 0xFFFFFFFF)
{
bActive = FALSE;
// 알파값 처리도 여기서 하자.
}
//else if(m_spRes->GetLifeTime() < 0)
else if(m_nLifeTime < 0)
//if(m_spRes->GetLifeTime() < 0)
{
bActive = TRUE;
// 알파값 처리도 여기서 하자.
}
//else if((int) m_dwCurrTime > m_spRes->GetLifeTime())
else if((int) m_dwCurrTime > m_nLifeTime)
{
bActive = FALSE;
// 알파값 처리도 여기서 하자.
}
else
{
bActive = TRUE;
// 알파값 처리도 여기서 하자.
}
//m_fCurrPos = m_fStartPos + (m_fVelocity * (float) m_dwCurrTime; / 1000.0f);
//if(m_fCurrPos < 0.0f) m_fCurrPos = 0.0f;
//if(m_fCurrPos > 1.0f) m_fCurrPos = 1.0f;
if(bActive)
{
//m_fCurrPos = m_spRes->GetStartPos() + (m_spRes->GetVelocity() * (float) m_dwCurrTime; / 1000.0f);
//if(m_fCurrPos < 0.0f) m_fCurrPos = 0.0f;
//if(m_fCurrPos > 1.0f) m_fCurrPos = 1.0f;
if(!m_bActive) // 지금 막 active 되었다.
{
if(m_pSeqModel) m_pSeqModel->PlayAnimation((DWORD) ((float) m_dwCurrTime / 4.8f), "default", KSeqModel::SEQTYPE_LOOP);
}
else
{
if(m_pSeqModel) m_pSeqModel->Process((DWORD) ((float) m_dwCurrTime / 4.8f));
}
}
m_bActive = bActive;
}
BOOL KEffectEmitter::IsActive()
{
return m_bActive;
}
//void KEffectEmitter::SetActive(BOOL bActive)
//{
// m_bActive = bActive;
//}
float KEffectEmitter::GetPos()
{
return m_fCurrPos;
}
void KEffectEmitter::SetPos(float fPos)
{
m_fCurrPos = fPos;
}
//void KEffectEmitter::SetSeqModel(KSeqModel* pSeqModel)
//{
// m_pSeqModel = pSeqModel;
//}
KSeqModel* KEffectEmitter::GetSeqModel()
{
return m_pSeqModel;
}
//float KEffectEmitter::GetAlpha()
//{
//}
DWORD KEffectEmitter::GetCurrTime()
{
return m_dwCurrTime;
}
void KEffectEmitter::CalcTimes(float fScale)
{
m_dwStartTime = (DWORD) ((float) m_spRes->GetStartTime() * fScale);
if(m_spRes->GetLifeTime() < 0)
{
m_nLifeTime = -1;
}
else
{
m_nLifeTime = (int) ((float) m_spRes->GetLifeTime() * fScale);
}
}
DWORD KEffectEmitter::GetStartTime()
{
return m_dwStartTime;
}
int KEffectEmitter::GetLifeTime()
{
return m_nLifeTime;
}
// _KSeqPathEffect
_KSeqPathEffect::_KSeqPathEffect()
{
m_spRes = NULL;
m_fTotalVertVectorLength = 0.0f;
m_dwDrawMode = 0;
//m_pTerrainEngine = NULL;
m_bActive = FALSE;
//m_bActive = TRUE;
//K3DMatrixIdentity(m_Mat);
m_pMat = NULL;
m_dwStartTime = 0;
m_dwLifeTime = 0;
}
_KSeqPathEffect::~_KSeqPathEffect()
{
Clear();
}
void _KSeqPathEffect::Clear()
{
m_vVerts.erase(m_vVerts.begin(), m_vVerts.end());
m_fTotalVertVectorLength = 0.0f;
// DelSeqModels();
DelEmitters();
DelPolyLineTex();
}
void _KSeqPathEffect::DelEmitters()
{
int size = m_vEmitters.size();
for(int i = 0; i < size; i++)
{
SAFE_DELETE(m_vEmitters[i]);
}
m_vEmitters.erase(m_vEmitters.begin(), m_vEmitters.end());
}
void _KSeqPathEffect::SetRes(KResPathEffect* pRes)
{
Clear();
m_spRes = pRes;
if(m_spRes == NULL)
return;
int size = m_spRes->GetNumEmitters();
for(int i = 0; i < size; i++)
{
KEffectEmitter* pEmitter = new KEffectEmitter;
pEmitter->SetRes(m_spRes->GetEmitter(i));
m_vEmitters.push_back(pEmitter);
}
m_prPolyLine.SetWidth(m_spRes->GetPolyLineWidth());
m_prPolyLine.SetColor(m_spRes->GetPolyLineColor());
CreatePolyLineTex();
m_dwStartTime = m_spRes->GetStartTime();
m_dwLifeTime = m_spRes->GetLifeTime();
}
KResPathEffect* _KSeqPathEffect::GetRes()
{
return m_spRes;
}
void _KSeqPathEffect::SetTime(DWORD dwTime)
{
//if(dwTime < m_spRes->GetStartTime()) m_dwTime = 0xFFFFFFFF;
//else m_dwTime = dwTime - m_spRes->GetStartTime();
if(dwTime < m_dwStartTime) m_dwTime = 0xFFFFFFFF;
else m_dwTime = dwTime - m_dwStartTime;
}
void _KSeqPathEffect::realizeTime()
{
if(m_dwRealizedTime == m_dwTime) return;
m_dwRealizedTime = m_dwTime;
if(m_dwRealizedTime == 0xFFFFFFFF)
{
m_bActive = FALSE;
}
//else if(m_spRes->GetLifeTime() < 0)
//{
// m_bActive = TRUE;
//}
//else if(m_dwRealizedTime > m_spRes->GetLifeTime())
else if(m_dwRealizedTime > m_dwLifeTime)
{
m_bActive = FALSE;
}
else
{
m_bActive = TRUE;
}
if(!m_bActive) return;
// 에미터들 업데이트
int size = m_vEmitters.size();
for(int i = 0; i < size; i++)
{
m_vEmitters[i]->Update(m_dwRealizedTime);
}
}
//BOOL _KSeqPathEffect::IsActive()
//{
// return m_bActive;
//}
void _KSeqPathEffect::AddVert(K3DVector vPos)
{
PfxPathVertex pathVert;
pathVert.vPos = vPos;
int numVert = m_vVerts.size();
if(numVert >= 1)
{
K3DVector v = vPos - m_vVerts[numVert - 1].vPos;
m_fTotalVertVectorLength += v.Magnitude();
}
pathVert.fLength = m_fTotalVertVectorLength;
m_vVerts.push_back(pathVert);
}
// 느리다.. 프리미티브는 디버그 할 때만 그리자.
void _KSeqPathEffect::UpdatePr()
{
int numVerts = (int)m_vVerts.size();
//if(numVerts < 2) return;
if(numVerts < 1) return;
int numEmitters = m_vEmitters.size();
//if(numEmitters < 2) return;
float fStartPos, fEndPos;
// 다~ 그린다.. 0.0부터 1.0까지..
if(m_dwDrawMode & DRAW_ALLPR)
{
fStartPos = 0.0f;
fEndPos = 1.0f;
}
else
{
if(numEmitters < 2) return;
// 에미터 벡터의 처음 두 개의 요소가 시작과 끝
if(!m_vEmitters[0]->IsActive() || !m_vEmitters[1]->IsActive()) return;
fStartPos = m_vEmitters[0]->GetPos();
fEndPos = m_vEmitters[1]->GetPos();
if(fStartPos >= fEndPos) return;
}
int nStart, nEnd;
K3DVector vStart, vEnd;
nStart = GetVert(fStartPos, vStart);
nEnd = GetVert(fEndPos, vEnd);
int dn = nEnd - nStart;
int size;
if(fEndPos == 1.0f) size = dn + 1;
else size = dn + 2;
// int numEmitters = m_vEmitters.size();
//KLinePrimitive::SVertex* pVerts = new KLinePrimitive::SVertex[size];
//PfxPrVertex* pVerts = new PfxPrVertex[size];
PfxPrVertex* pVerts = new PfxPrVertex[size + numEmitters];
DWORD dwColor = 0xFFFFFF00; // 노란색
//pVerts[0].pos = vStart;
pVerts[0].pos.x = vStart.x;
pVerts[0].pos.y = vStart.y;
pVerts[0].pos.z = vStart.z;
pVerts[0].color = dwColor;
for(int i = 1; i <= dn; i++)
{
//pVerts[i].pos = m_vVerts[i + nStart];
pVerts[i].pos.x = m_vVerts[i + nStart].vPos.x;
pVerts[i].pos.y = m_vVerts[i + nStart].vPos.y;
pVerts[i].pos.z = m_vVerts[i + nStart].vPos.z;
pVerts[i].color = dwColor;
}
// emEnd->GetPos() == 1.0f 이라면 마지막 점은 이미 추가가 되었다.
if(fEndPos != 1.0f)
{
//pVerts[dn + 1].pos = vEnd;
pVerts[dn + 1].pos.x = vEnd.x;
pVerts[dn + 1].pos.y = vEnd.y;
pVerts[dn + 1].pos.z = vEnd.z;
pVerts[dn + 1].color = dwColor;
}
for(int i = 0; i < numEmitters; i++)
{
K3DVector vEmitter;
int nRet = GetVert(m_vEmitters[i]->GetPos(), vEmitter);
dwColor = 0xFFFF0000; // 붉은색.. 아마도..
pVerts[size + i].pos.x = vEmitter.x;
pVerts[size + i].pos.y = vEmitter.y;
pVerts[size + i].pos.z = vEmitter.z;
pVerts[size + i].color = dwColor;
}
//if(m_dwDrawMode & DRAW_POINT) m_prQuad.Update(pVerts, size);
if(m_dwDrawMode & DRAW_POINT) m_prQuad.Update(pVerts, size + numEmitters); // 에미터 쿼드도 함께 그린다.
if(m_dwDrawMode & DRAW_LINE) m_prLine.Update(pVerts, size);
delete[] pVerts;
}
int _KSeqPathEffect::GetVert(float fPos, K3DVertex& vRes)
{
if(fPos < 0.0f || fPos > 1.0f) return -1; // 에러
int numVert = m_vVerts.size();
int n;
if(fPos == 1.0f) // 예외 처리
{
vRes = m_vVerts[numVert - 1].vPos;
return (numVert - 1);
}
fPos *= m_fTotalVertVectorLength; // 절대 좌표값으로 바꾼다.
for(n = 0; n < numVert; n++)
{
if(m_vVerts[n].fLength > fPos) break;
}
--n;
float fraction = fPos - m_vVerts[n].fLength;
K3DVector vec = m_vVerts[n + 1].vPos - m_vVerts[n].vPos;
fraction /= vec.Magnitude();
vRes = m_vVerts[n].vPos + vec * fraction;
return n;
}
void _KSeqPathEffect::SetDrawMode(DWORD dwMode)
{
m_dwDrawMode = dwMode;
}
void _KSeqPathEffect::Render(KViewportObject* viewport, DWORD flag, const K3DMatrix* pAttachMat)
{
//realizeTime(); // KSeqPathEffectChain에서 해주니까 여기선 호출할 필요 없다.
// 프리미티브는 m_bActive == FALSE 라도 그린다.
if((m_dwDrawMode & DRAW_POINT) || (m_dwDrawMode & DRAW_LINE)) UpdatePr();
if(m_dwDrawMode & DRAW_POINT) viewport->Register(&m_prQuad, KRenderObject::RENDEREFX_QUAD);
if(m_dwDrawMode & DRAW_LINE) viewport->Register(&m_prLine, KRenderObject::RENDEREFX_LINE);
if((m_dwDrawMode & DRAW_POLYLINE) && m_bActive) RenderPolyLine(viewport);
if((m_dwDrawMode & DRAW_EMITTER) && m_bActive)
{
int numEmitters = m_vEmitters.size();
for(int i = 0; i < numEmitters; i++)
{
if(m_vEmitters[i]->IsActive())
{
RenderEmitter(i, viewport);
}
}
}
}
static inline void K3DMatrixSetDirection( K3DMatrix &Out, const K3DVector &StartPos, const K3DVector &EndPos )
{
K3DVector xVector, yVector, zVector;
yVector = StartPos-EndPos;
Normalize(yVector);
zVector = K3DVector( 0, 0, 1 );
K3DVectorCross( xVector, zVector, yVector );
Normalize(xVector);
K3DVectorCross( zVector, xVector, yVector );
Normalize(zVector);
// K3DMatrixIdentity( Out );
Out._11 = xVector.x; Out._12 = xVector.y; Out._13 = xVector.z;
Out._21 = yVector.x; Out._22 = yVector.y; Out._23 = yVector.z;
Out._31 = zVector.x; Out._32 = zVector.y; Out._33 = zVector.z;
}
void _KSeqPathEffect::RenderEmitter(int nEmitter, KViewportObject* viewport)
{
// vPos 위치에 SeqModel을 그린다
KSeqModel* pSeqModel = m_vEmitters[nEmitter]->GetSeqModel();
if(!pSeqModel) return;
// 정점이 없어도 에미터는 그릴 수 없다
int numVerts = m_vVerts.size();
if(numVerts < 1) return;
KResEffectEmitter* pResEmitter = m_vEmitters[nEmitter]->GetRes();
if(!pResEmitter) assert(0);
float fCurrPos = pResEmitter->GetStartPos() + (pResEmitter->GetVelocity() / m_fTotalVertVectorLength * (float) m_vEmitters[nEmitter]->GetCurrTime() / 1000.0f);
if(fCurrPos < 0.0f) fCurrPos = 0.0f;
if(fCurrPos > 1.0f) fCurrPos = 1.0f;
m_vEmitters[nEmitter]->SetPos(fCurrPos);
K3DVector vPos1, vPos2;
K3DMatrix mat;
int n = GetVert(m_vEmitters[nEmitter]->GetPos(), vPos1);
//int n = GetVert(fCurrPos, vPos1);
K3DMatrixIdentity(mat);
if(numVerts == 1 || !m_vEmitters[nEmitter]->GetRes()->IsDirectional())
{
mat.SetPosVector(vPos1);
}
else // numVerts > 1 && m_vEmitters[nEmitter]->GetRes()->IsDirectional()
{
mat.SetPosVector(vPos1);
if(n < numVerts - 1)
{
vPos2 = m_vVerts[n + 1].vPos;
K3DMatrixSetDirection(mat, vPos1, vPos2);
}
else // n == numVerts - 1;
{
vPos2 = m_vVerts[n - 1].vPos;
K3DMatrixSetDirection(mat, vPos2, vPos1);
}
K3DVector vX;
K3DMatrixGetXVector(vX, mat);
vX *= -1.0f;
mat.SetXVector(vX);
K3DVector vZ;
K3DMatrixGetZVector(vZ, mat);
vZ *= -1.0f;
mat.SetZVector(vZ);
}
pSeqModel->SetTransform(mat);
pSeqModel->Render(viewport);
}
void _KSeqPathEffect::RenderPolyLine(KViewportObject* viewport)
{
int numVerts = m_vVerts.size();
if(numVerts < 2) return;
int numEmitters = m_vEmitters.size();
if(numEmitters < 2) return;
if(!m_spRes->HasPolyLine() || !m_spPolyLineTex) return;
float fStartPos, fEndPos;
// 에미터 벡터의 처음 두 개의 요소가 시작과 끝
if(!m_vEmitters[0]->IsActive() || !m_vEmitters[1]->IsActive()) return;
fStartPos = m_vEmitters[0]->GetPos();
fEndPos = m_vEmitters[1]->GetPos();
m_prPolyLine.Update(fStartPos, fEndPos);
viewport->Register(&m_prPolyLine, KRenderObject::RENDEREFX_POLYLINE);
}
void _KSeqPathEffect::SetTerrainEngine(CTerrainMapEngine* pTerrain)
{
m_pTerrainEngine = pTerrain;
}
void _KSeqPathEffect::SetMat(K3DMatrix* pMat)
{
m_pMat = pMat;
}
void _KSeqPathEffect::CreatePolyLineTex()
{
const char* szTexName = m_spRes->GetPolyLineTexName();
if(strcmp(szTexName, PFX_NOTEX) == 0) return;
//TODO : 리소스 옵션 로딩 추가 작업 중.
NX3LoadPack loadpack;
loadpack.Init();
m_spPolyLineTex = KTextureManager::GetManager()->GetTexture(szTexName, &loadpack, true, KTextureManager::GetManager()->GetMipMapBiasLevel());
m_prPolyLine.SetTexture(m_spPolyLineTex);
}
void _KSeqPathEffect::DelPolyLineTex()
{
m_prPolyLine.SetTexture(NULL);
}
void _KSeqPathEffect::CalcTimes()
{
//float fNewScale = fScale * m_fTotalVertVectorLength / m_spRes->GetTotalPointVectorLength();
float fScale = m_fTotalVertVectorLength / m_spRes->GetTotalPointVectorLength();
m_dwStartTime = (DWORD) ((float) m_spRes->GetStartTime() * fScale);
m_dwLifeTime = (DWORD) ((float) m_spRes->GetLifeTime() * fScale);
int size = m_vEmitters.size();
for(int i = 0; i < size; i++)
{
m_vEmitters[i]->CalcTimes(fScale);
}
}
DWORD _KSeqPathEffect::GetStartTime()
{
return m_dwStartTime;
}
DWORD _KSeqPathEffect::GetLifeTime()
{
return m_dwLifeTime;
}
void _KSeqPathEffect::SetLifeTime(DWORD dwLifeTime)
{
m_dwLifeTime = dwLifeTime;
}
// KSeqPathEffect
KSeqPathEffect::KSeqPathEffect()
{
}
KSeqPathEffect::~KSeqPathEffect()
{
}
KSeqObject* KSeqPathEffect::Clone()
{
KSeqPathEffect *obj = new KSeqPathEffect;
obj->SetRes(m_spRes);
return obj;
}
void KSeqPathEffect::Update()
{
int oldCap = m_vVerts.capacity();
int newCap = m_spRes->GetNumPoints();
if(oldCap < newCap) m_vVerts.reserve(newCap);
m_vVerts.erase(m_vVerts.begin(), m_vVerts.end());
m_fTotalVertVectorLength = 0.0f;
if(m_dwDrawMode & DRAW_POLYLINE) m_prPolyLine.Clear();
PointsToVerts();
if(m_dwDrawMode & DRAW_POLYLINE) m_prPolyLine.Update();
}
// 느림.. 에디터용
void KSeqPathEffect::PointsToVerts()
{
int size = m_spRes->GetNumPoints();
K3DPoint* pPoints = m_spRes->GetPoints();
for(int i = 0; i < size; i++)
{
K3DVector vTemp, vRes;
vTemp.x = pPoints[i].x;
vTemp.y = pPoints[i].y;
vTemp.z = 0.0f;
if(m_pMat) K3DVectorTransform(vRes, vTemp, *m_pMat);
else vRes = vTemp;
vRes.z = m_spRes->GetOfsZ();
AddVert(vRes);
if(m_dwDrawMode & DRAW_POLYLINE)
{
m_prPolyLine.AddPathVert(vRes);
m_prPolyLine.AddPathNormal(K3DVector(0.0f, 0.0f, 1.0f));
}
}
}
// KSeqPathEffectGround
KSeqPathEffectGround::KSeqPathEffectGround()
{
}
KSeqPathEffectGround::~KSeqPathEffectGround()
{
}
KSeqObject* KSeqPathEffectGround::Clone()
{
KSeqPathEffectGround *obj = new KSeqPathEffectGround;
obj->SetRes(m_spRes);
return obj;
}
namespace
{
float OFS_XY = 1.0f;
}
// m_vPoints를 땅에 붙여서 m_vVerts를 얻는다. - 매 프레임마다 호출할 필요 없다. 처음 이펙트가 시작될 때나 패쓰의 변경이 있을때만 호출해주면 된다.
void KSeqPathEffectGround::Update()
{
if(!m_pTerrainEngine)
{
assert(0 && "SetTerrainEngine() 부터 먼저 호출하셔.");
return;
}
int oldCap = m_vVerts.capacity();
//int newCap = (int) (m_fTotalPointVectorLength / pTerrain->GetTileLength() * 4.0f); // 대개의 경우 4.0f는 충분한 값이다.
int newCap = (int) (m_spRes->GetTotalPointVectorLength() / m_pTerrainEngine->GetTileLength() * 4.0f); // 대개의 경우 4.0f는 충분한 값이다.
if(oldCap < newCap) m_vVerts.reserve(newCap);
m_vVerts.erase(m_vVerts.begin(), m_vVerts.end());
m_fTotalVertVectorLength = 0.0f;
if(m_dwDrawMode & DRAW_POLYLINE) m_prPolyLine.Clear();
AttachToTerrain();
if(m_dwDrawMode & DRAW_POLYLINE) m_prPolyLine.Update();
}
void KSeqPathEffectGround::AttachToTerrain()
{
//int numPoints = m_vPoints.size();
int numPoints = m_spRes->GetNumPoints();
for(int i = 0; i < numPoints - 1; i++)
{
//AttachToTerrain(m_vPoints[i], m_vPoints[i + 1]);
AttachToTerrain(m_spRes->GetPoint(i), m_spRes->GetPoint(i + 1));
}
// 마지막 점은 수동으로 벡터 변수에 넣어줘야 한다.
//int n = numPoints - 1;
K3DPoint lastPoint = m_spRes->GetPoint(numPoints - 1);
K3DVector vTemp, vTarget;
vTemp.x = lastPoint.x;
vTemp.y = lastPoint.y;
vTemp.z = 0.0f;
if(m_pMat)
{
K3DVectorTransform(vTarget, vTemp, *m_pMat);
}
else
{
vTarget = vTemp;
}
K3DVector v[3];
//m_pTerrainEngine->GetTerrainTriangle(m_vPoints[n].x, m_vPoints[n].y, v[0], v[1], v[2]);
m_pTerrainEngine->GetTerrainTriangle(vTarget.x, vTarget.y, v[0], v[1], v[2]);
// 높이 구하고
//float fTilt1 = ( m_vPoints[n].y - (v[0].y) ) / ( (v[1].y) - (v[0].y) );
//float fTilt2 = ( m_vPoints[n].y - (v[0].y) ) / ( (v[2].y) - (v[0].y) );
float fTilt1 = (vTarget.y - (v[0].y)) / ((v[1].y) - (v[0].y));
float fTilt2 = (vTarget.y - (v[0].y)) / ((v[2].y) - (v[0].y));
float z1 = v[0].z + ( v[1].z - v[0].z ) * fTilt1;
float x1 = v[0].x + ( v[1].x - v[0].x ) * fTilt1;
float z2 = v[0].z + ( v[2].z - v[0].z ) * fTilt2;
float x2 = v[0].x + ( v[2].x - v[0].x ) * fTilt2;
//float fHeight = z1 + ( z2 - z1 ) * ( m_vPoints[n].x - x1 ) / ( x2 - x1 );
float fHeight = z1 + (z2 - z1) * (vTarget.x - x1) / (x2 - x1);
// 이 점을 멤버 벡터 변수에 추가
//K3DVector vRes(m_vPoints[n].x, m_vPoints[n].y, fHeight + m_fOfsZ);
K3DVector vRes(vTarget.x, vTarget.y, fHeight + m_spRes->GetOfsZ());
//m_vVerts.push_back(vRes);
AddVert(vRes);
if(m_dwDrawMode & DRAW_POLYLINE)
{
m_prPolyLine.AddPathVert(vRes);
K3DVector vec1, vec2;
vec1 = v[1] - v[0];
vec2 = v[2] - v[0];
K3DVector normal = CrossProduct(vec1, vec2);
//K3DVector normal = CrossProduct(vec2, vec1);
Normalize(normal);
m_prPolyLine.AddPathNormal(normal);
}
}
void KSeqPathEffectGround::AttachToTerrain(K3DPoint p1, K3DPoint p2)
{
K3DVector vTemp1, vTemp2, vTarget1, vTarget2;
vTemp1.x = p1.x;
vTemp1.y = p1.y;
vTemp1.z = 0.0f;
vTemp2.x = p2.x;
vTemp2.y = p2.y;
vTemp2.z = 0.0f;
if(m_pMat)
{
K3DVectorTransform(vTarget1, vTemp1, *m_pMat);
K3DVectorTransform(vTarget2, vTemp2, *m_pMat);
}
else
{
vTarget1 = vTemp1;
vTarget2 = vTemp2;
}
K3DVector v[3];
m_pTerrainEngine->GetTerrainTriangle(vTarget1.x, vTarget1.y, v[0], v[1], v[2]);
// 높이 구하고
float fTilt1 = ( vTarget1.y - (v[0].y) ) / ( (v[1].y) - (v[0].y) );
float fTilt2 = ( vTarget1.y - (v[0].y) ) / ( (v[2].y) - (v[0].y) );
float z1 = v[0].z + ( v[1].z - v[0].z ) * fTilt1;
float x1 = v[0].x + ( v[1].x - v[0].x ) * fTilt1;
float z2 = v[0].z + ( v[2].z - v[0].z ) * fTilt2;
float x2 = v[0].x + ( v[2].x - v[0].x ) * fTilt2;
float fHeight = z1 + ( z2 - z1 ) * ( vTarget1.x - x1 ) / ( x2 - x1 );
// 이 점을 멤버 벡터 변수에 추가
//K3DVector vRes(p1.x, p1.y, fHeight + m_fOfsZ);
K3DVector vRes(vTarget1.x, vTarget1.y, fHeight + m_spRes->GetOfsZ());
//m_vVerts.push_back(vRes);
AddVert(vRes);
if(m_dwDrawMode & DRAW_POLYLINE)
{
m_prPolyLine.AddPathVert(vRes);
K3DVector vec1, vec2;
vec1 = v[1] - v[0];
vec2 = v[2] - v[0];
K3DVector normal = CrossProduct(vec1, vec2);
//K3DVector normal = CrossProduct(vec2, vec1);
Normalize(normal);
m_prPolyLine.AddPathNormal(normal);
}
// p1p2 벡터와 삼각형의 세 모서리와의 교점 및 t를 구하고
float fraction = 1.0f;
float t1, t2, denom;
//float x1 = p1.x; float x2 = p2.x;
//x1 = p1.x; x2 = p2.x;
x1 = vTarget1.x; x2 = vTarget2.x;
//float y1 = p1.y; float y2 = p2.y;
float y1 = vTarget1.y; float y2 = vTarget2.y;
float x3, x4, y3, y4;
for(int i = 0; i < 3; i++)
{
x3 = v[i].x; x4 = v[(i + 1) % 3].x;
y3 = v[i].y; y4 = v[(i + 1) % 3].y;
denom = ((y4- y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1));
if(fabsf(denom) < 0.001f) continue;
t1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3));
t1 /= denom;
if(t1 <= 0.0f || t1 >= 1.0f) continue;
t2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3));
t2 /= denom;
if(t2 <= 0.0f || t2 >= 1.0f) continue;
if(t1 < fraction) fraction = t1;
}
//float offset = 0.1f;
//float offset = 1.0f;
// 아주 작은 값을 더해서 얻은 점을 포함하는 삼각형을 또 구한다
// 이것을 fraction >= 1.0f 일 때까지 반복
if(fraction < 1.0f)
//if(fraction < 0.999f)
{
//fraction += e; // 이렇게 하면 안되고
K3DPoint pVec = p2 - p1;
K3DPoint pNew = p1 + pVec * fraction;
K3DPoint pVecTemp = p2 - pNew;
if(sqrtf(pVecTemp.x * pVecTemp.x + pVecTemp.y * pVecTemp.y) <= OFS_XY) return;
// 이렇게 해야지
float mag = sqrtf(pVec.x * pVec.x + pVec.y * pVec.y);
pVec /= mag;
//pNew = pNew + pVec * m_fOfsXY;
pNew = pNew + pVec * OFS_XY;
AttachToTerrain(pNew, p2);
}
}
// KSeqPathEffectChain
//
// 멤버 함수 호출 순서
// 1. 생성
// 2. SetTerrainEngine() - KSeqPathEffectGround
// 3. SetType() - KSeqPathEffect
// 4. SetRes() - 로드할때 자동 호출
// 5. SetDrawMode()
// 6. SetPos()
// 7. Update() - SetPos()에서 자동 호출
// 8. SetTime() - Loop
// 9. Render() - Loop
// 10. 파괴
KSeqPathEffectChain::KSeqPathEffectChain()
{
// m_dwStartTime = 0;
m_dwDrawMode = 0;
//m_dwDrawMode = _KSeqPathEffect::DRAW_EMITTER;
//m_pTerrainEngine = NULL;
//m_dwType = TYPE_ORDINARY;
m_dwType = TYPE_GROUND;
//m_bDirectional = FALSE;
K3DMatrixIdentity(m_Mat);
}
KSeqPathEffectChain::~KSeqPathEffectChain()
{
Clear();
}
void KSeqPathEffectChain::SetType(DWORD dwType)
{
m_dwType = dwType;
}
void KSeqPathEffectChain::Clear()
{
//SAFE_DELETE(m_spRes);
DelPathEffects();
//DelSeqModels();
}
KSeqObject* KSeqPathEffectChain::Clone()
{
KSeqPathEffectChain *obj = new KSeqPathEffectChain;
obj->SetType(m_dwType);
obj->SetRes(m_spRes);
return obj;
}
void KSeqPathEffectChain::SetRes(KResPathEffectChain* pRes)
{
Clear();
m_spRes = pRes;
if(m_spRes == NULL)
return;
int size = m_spRes->GetNumPathEffects();
m_interval.SetStart(0);
int nEnd = 0;
for(int i = 0; i < size; i++)
{
_KSeqPathEffect* pPathEffect = NULL;
if(m_dwType == TYPE_ORDINARY)
{
pPathEffect = new KSeqPathEffect;
}
else if(m_dwType == TYPE_GROUND)
{
pPathEffect = new KSeqPathEffectGround;
}
else
{
assert(0 && "m_dwType 에 쓰레기값이..!");
return;
}
pPathEffect->SetRes(m_spRes->GetPathEffect(i));
pPathEffect->SetDrawMode(m_dwDrawMode); // 새로 추가되는 pfx에 pfxchain의 DrawMode를 적용한다.
m_vPathEffects.push_back(pPathEffect);
if(nEnd < (int) (m_spRes->GetPathEffect(i)->GetStartTime() + m_spRes->GetPathEffect(i)->GetLifeTime()))
nEnd = (int) (m_spRes->GetPathEffect(i)->GetStartTime() + m_spRes->GetPathEffect(i)->GetLifeTime());
}
m_interval.SetEnd(nEnd);
}
KResPathEffectChain* KSeqPathEffectChain::GetRes()
{
return m_spRes;
}
void KSeqPathEffectChain::SetTime(DWORD dwTime)
{
m_dwTime = dwTime;
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->SetTime(m_dwTime);
}
}
void KSeqPathEffectChain::realizeTime()
{
if(m_dwRealizedTime == m_dwTime) return;
m_dwRealizedTime = m_dwTime;
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->realizeTime();
}
}
void KSeqPathEffectChain::Update()
{
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->Update();
}
}
void KSeqPathEffectChain::Render(KViewportObject* viewport, DWORD flag, const K3DMatrix* pAttachMat)
{
realizeTime();
int size = (int)m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
//if(m_vPathEffects[i]->IsActive())
//{
m_vPathEffects[i]->Render(viewport, flag, pAttachMat);
//}
}
}
void KSeqPathEffectChain::DelPathEffects()
{
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
SAFE_DELETE(m_vPathEffects[i]);
}
m_vPathEffects.erase(m_vPathEffects.begin(), m_vPathEffects.end());
}
//void KSeqPathEffectChain::SetDrawMode()
//{
// int size = m_vPathEffects.size();
//
// for(int i = 0; i < size; i++)
// {
// m_vPathEffects[i]->SetDrawMode(m_dwDrawMode);
// }
//}
//void KSeqPathEffectChain::SetDrawMode(DWORD dwDrawMode)
//{
// m_dwDrawMode = dwDrawMode;
//
// SetDrawMode();
//}
void KSeqPathEffectChain::SetDrawMode(DWORD dwDrawMode)
{
m_dwDrawMode = dwDrawMode;
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->SetDrawMode(m_dwDrawMode);
}
}
void KSeqPathEffectChain::SetTerrainEngine(CTerrainMapEngine* pTerrain)
{
m_pTerrainEngine = pTerrain;
//int size = m_vPathEffects.size();
//for(int i = 0; i < size; i++)
//{
// m_vPathEffects[i]->SetTerrainEngine(m_pTerrainEngine);
//}
_KSeqPathEffect::SetTerrainEngine(m_pTerrainEngine);
}
//BOOL KSeqPathEffectChain::LoadSeqModels()
//{
// if(!m_spRes) return FALSE;
//
// int size = m_spRes->GetNumSeqModels();
//
// for(int i = 0; i < size; i++)
// {
// const char* szName = m_spRes->GetSeqModelName(i);
//
// KSeqModel* pSeqModel = new KSeqModel;
// pSeqModel->
// }
//}
//void KSeqPathEffectChain::DelSeqModels()
//{
// int size = m_vSeqModels.size();
//
// for(int i = 0; i < size; i++)
// {
// SAFE_DELETE(m_vSeqModels[i]);
// }
//
// m_vSeqModels.erase(m_vSeqModels.begin(), m_vSeqModels.end());
//}
void KSeqPathEffectChain::SetPos(K3DVector vOrigin)
{
K3DMatrixIdentity(m_Mat);
m_Mat.SetPosVector(vOrigin);
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->SetMat(&m_Mat);
}
Update();
CalcTimes();
}
void KSeqPathEffectChain::SetPos(K3DVector vOrigin, K3DVector vTarget)
{
//if(!m_bDirectional)
if(!m_spRes->IsDirectional())
{
// 이동만..
SetPos(vOrigin);
}
else
{
// 회전, 스케일, 이동
K3DMatrix matS, matTR;
K3DMatrixIdentity(m_Mat);
K3DMatrixIdentity(matS);
K3DMatrixIdentity(matTR);
K3DVector vDir = vTarget - vOrigin;
float fScale = vDir.Magnitude() / m_spRes->GetMag();
K3DMatrixScaling(matS, fScale, fScale, fScale);
matTR.SetPosVector(vOrigin);
K3DMatrixSetDirection(matTR, vOrigin, vTarget);
K3DVector vX;
K3DMatrixGetXVector(vX, matTR);
vX *= -1.0f;
matTR.SetXVector(vX);
K3DVector vZ;
K3DMatrixGetZVector(vZ, matTR);
vZ *= -1.0f;
matTR.SetZVector(vZ);
K3DMatrixMultiply(m_Mat, matS, matTR);
int size = m_vPathEffects.size();
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->SetMat(&m_Mat);
}
Update();
CalcTimes();
}
}
void KSeqPathEffectChain::CalcTimes()
{
int size = m_vPathEffects.size();
m_interval.SetStart(0);
int nEnd = 0;
for(int i = 0; i < size; i++)
{
m_vPathEffects[i]->CalcTimes();
if(nEnd < (int) (m_vPathEffects[i]->GetStartTime() + m_vPathEffects[i]->GetLifeTime()))
nEnd = (int) (m_vPathEffects[i]->GetStartTime() + m_vPathEffects[i]->GetLifeTime());
}
m_interval.SetEnd(nEnd);
if(m_spRes->DoesEndTogether())
{
DWORD dwLifeTime;
for(int i = 0; i < size; i++)
{
dwLifeTime = (DWORD) nEnd - m_vPathEffects[i]->GetStartTime();
m_vPathEffects[i]->SetLifeTime(dwLifeTime);
}
}
}