#include "stdafx.h" #include "KSeqPathEffect.h" #include #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); } } }