// ParticleSystem.cpp: implementation of the CParticleSystem class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "effect.h"
#include "ParticleSystem.h"
//#include "AtumApplication.h"


//extern CAtumApplication				*g_pD3dApp;

#include "MainFrm.h"
#include "MapEditor.h"
#include "MapEditorDoc.h"
#include "MapEditorView.h"

//////////////////////////////////////////////////////////////////////
// CParticle 
//////////////////////////////////////////////////////////////////////

CParticle::CParticle(int nParticleType)
{
	fDistance = 0.0f;
	dwType = EFFECT_TYPE_PARTICLE;

	m_nParticleType  = nParticleType;//DELETE
	m_fSize = 0;
	m_fLifeTime = 0;
	m_fCurrentLifeTime = 0;

	m_cColor = D3DXCOLOR(0,0,0,0);
	m_cColorStep = D3DXCOLOR(0,0,0,0);
	m_vPos = D3DXVECTOR3(0,0,0);
	m_vVel = D3DXVECTOR3(0,0,0);
	m_vDir = D3DXVECTOR3(0,0,0);

	m_fTextureSizeVel = 0; 
	m_fTextureStartSize = 0;
	m_fTextureSizeMax = 0; 
	m_fTextureSizeMin = 0;
	m_nTextureSizeChangeType = 0;
	m_fCurrentTextureAnimationTime = 0;
	m_nTextureNumber = 0;

	m_fGravity = 0;

	m_nPersistence = 0;
	m_fColorChangeStartTime = 0;
	m_fCurrentRotateAngle = 0;
	m_fCurrentRotateTime = 0;
	m_vStartPos = D3DXVECTOR3(0,0,0);
	m_pParent = NULL;
	m_pObjectAni = NULL;

}

CParticle::~CParticle()
{
}

BOOL CParticle::Tick(float fElapsedTime)
{
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	CMapEditorView* pView = (CMapEditorView*)pFrame->GetActiveView();
	m_fLifeTime -= fElapsedTime;
	m_fCurrentLifeTime += fElapsedTime;
	if(m_fLifeTime<0)
	{
		return FALSE;
	}
	if(m_fRotateAngle == 0)
	{
		m_vPos += m_vVel * m_fCurrentLifeTime + m_vDir * fElapsedTime;//방향 및 가속도
	} else
	{
		D3DXMATRIX	matTemp;
		D3DXVECTOR3 vPos;
		m_vPos += m_vVel * m_fCurrentLifeTime;
		D3DXMatrixRotationAxis( &matTemp, &m_vDir, m_fRotateAngle );
		vPos = m_vPos - m_vStartPos;
//		D3DXVec3TransformCoord( &m_vPos, &m_vPos, &matTemp );
//		D3DXVec3Normalize( &vTemp, &m_vPos );
		D3DXVec3TransformCoord( &vPos, &vPos, &matTemp );
		m_vPos = vPos + m_vStartPos;
		D3DXVec3Normalize( &vPos, &vPos );
		m_vPos += vPos*m_fCircleForce;
	}
	m_vPos.y -= m_fGravity * m_fCurrentLifeTime;// 중력

	if(m_nTextureSizeChangeType != TEXTURE_SIZE_FIX ||// 텍스쳐 애니메이션 타임
		m_nTextureAnimationType != TEXTURE_ANIMATION_RANDOM)
	{	
		m_fCurrentTextureAnimationTime += fElapsedTime;
		if(m_fTextureAnimationTime > 0 && m_fCurrentTextureAnimationTime > m_fTextureAnimationTime)
		{
/*			if(m_nTextureSizeChangeType == TEXTURE_SIZE_RANDOM)// 텍스쳐 사이즈
			{
				m_fSize = Random(m_fTextureSizeMax, m_fTextureSizeMin);
			} 
			else 
*/			if( m_nTextureSizeChangeType == TEXTURE_SIZE_STEP)
			{
				m_fSize += m_fTextureSizeVel;
				if( m_fSize < 0 )
					return FALSE;
			}

			switch(m_nTextureAnimationType)// 텍스쳐 애니메이션
			{
			case TEXTURE_ANIMATION_RANDOM:
				{
					m_nTextureType = rand()%m_nTextureNumber;
				}
				break;
			case TEXTURE_ANIMATION_STEP:
				{
					m_nTextureType ++;
					if(m_nTextureType >= m_nTextureNumber)
						m_nTextureType = 0;
				}
				break;
			}

			m_fCurrentTextureAnimationTime = 0;
		}

	}
	switch(m_nParticleType)
	{
	case PARTICLE_OBJECT_TYPE:
		{
			if(m_pObjectAni)
			{
				if(!m_pObjectAni->Tick(fElapsedTime))
				{
					return FALSE;
				}
			}
		}
		break;
	case PARTICLE_SPRITE_TYPE:
		{
			m_fColorChangeStartTime -= fElapsedTime;
			if(m_fColorChangeStartTime<=0 && ((DWORD)m_cColor) != 0 && 
				(m_cColorStep.r!=0 || m_cColorStep.g!=0 || m_cColorStep.b!=0 || m_cColorStep.a!=0))
			{
				m_cColor += m_cColorStep*(fElapsedTime/0.03f);//60(0.015):x2, 30(0.03):x4
				if(m_cColor.r < 0 ) m_cColor.r = 0;
				if(m_cColor.g < 0 ) m_cColor.g = 0;
				if(m_cColor.b < 0 ) m_cColor.b = 0;
				if(m_cColor.a < 0 ) m_cColor.a = 0;
				if(m_cColor.r > 1 ) m_cColor.r = 1;
				if(m_cColor.g > 1 ) m_cColor.g = 1;
				if(m_cColor.b > 1 ) m_cColor.b = 1;
				if(m_cColor.a > 1 ) m_cColor.a = 1;
				if((DWORD)m_cColor == 0 )
				{
					if(m_pParent->m_bColorLoop)
					{
						m_cColorStep *= -1;
						m_cColor += m_cColorStep;
					}
					else
					{
						return FALSE;
					}
				}
				else if( (DWORD)m_cColor == 0xFFFFFFFF )
				{
					if(m_pParent->m_bColorLoop)
					{
						m_cColorStep *= -1;
						m_cColor += m_cColorStep;
					}
				}
			}
			if(m_pParent && m_pParent->m_pParent 
				&& m_pParent->m_pParent->m_fBillboardRotateAngle>0
				&& m_pParent->m_pParent->m_fBillboardRotatePerSec > 0)
			{
				m_fCurrentRotateTime += fElapsedTime;
				if(m_fCurrentRotateTime > m_pParent->m_pParent->m_fBillboardRotatePerSec)
				{
					m_fCurrentRotateAngle += m_pParent->m_pParent->m_fBillboardRotateAngle;
					m_fCurrentRotateTime = 0;
				}
			}
		}
		break;
	}
	if(m_pParent->m_bZbufferEnable)
	{
		fDistance = D3DXVec3Length(&(pView->m_pCamera->GetEyePt()-m_vPos));
//		fDistance = D3DXVec3Dot(&(pView->m_pCamera->GetViewDir()), &m_vPos);
	}
	return TRUE;
}


HRESULT CParticle::InitDeviceObjects()
{
//	m_vStartPos = m_vPos;
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	CMapEditorView* pView = (CMapEditorView*)pFrame->GetActiveView();
	switch(m_nParticleType)
	{
	case PARTICLE_OBJECT_TYPE:
		{
			char* pEffect = new char[sizeof(ParticleData)];//임의의 큰 사이즈
//			DWORD type = g_pD3dApp->m_pEffectRender->LoadEffect(m_pParent->m_strTextureName[m_nTextureType], m_nParticleType, pEffect);
			DWORD type = pView->m_pEffectRender->LoadEffect(m_pParent->m_strTextureName[m_nTextureType], m_nParticleType, pEffect);
			if(m_pObjectAni)
			{
				m_pObjectAni->InvalidateDeviceObjects();
				m_pObjectAni->DeleteDeviceObjects();
				SAFE_DELETE(m_pObjectAni);

			}
			m_pObjectAni = new CObjectAni();
			memcpy( (void*)((char*)m_pObjectAni+sizeof(Effect)), pEffect, sizeof(ObjectAniData)-sizeof(Effect));
			m_pObjectAni->m_pParent = m_pParent->m_pParent;// 부모의 부모(EffectInfo)
			m_pObjectAni->InitDeviceObjects();
			m_pObjectAni->RestoreDeviceObjects();
			delete pEffect;
			pEffect = NULL;
		}
		break;
	case PARTICLE_SPRITE_TYPE:
		{
		}
		break;
	}
	return S_OK;
}

HRESULT CParticle::RestoreDeviceObjects()
{
	return S_OK;
}

HRESULT CParticle::InvalidateDeviceObjects()
{
	return S_OK;
}

HRESULT CParticle::DeleteDeviceObjects()
{
	switch(m_nParticleType)
	{
	case PARTICLE_OBJECT_TYPE:
		{
			m_pObjectAni->InvalidateDeviceObjects();
			m_pObjectAni->DeleteDeviceObjects();
			SAFE_DELETE(m_pObjectAni);
			m_pObjectAni = NULL;
		}
		break;
	case PARTICLE_SPRITE_TYPE:
		{
		}
		break;
	}
	return S_OK;
}

//////////////////////////////////////////////////////////////////////
// CParticleSystem 
//////////////////////////////////////////////////////////////////////

CParticleSystem::CParticleSystem()
{
	m_dwStateBlock = 0;
	m_bLoop = FALSE;
	m_dwDestBlend = 1;
	m_dwSrcBlend = 1;
	m_nEmitMass = 0;
	m_fEmitTime = 0.0f;
	m_fGravity = 0.0f;
//	m_fLifeTime = 0.0f;
	m_fDelayTime = 0.0f;
	m_cStartColor = D3DXCOLOR(0,0,0,0);
	m_cColorVel = D3DXCOLOR(0,0,0,0);
	m_vVel = D3DXVECTOR3(0,0,0);
	m_fTextureSizeVel = 0.0f;
	m_fTextureStartSize = 0.0f;
	m_fTextureSizeMax = 0.0f;
	m_fTextureSizeMin = 0.0f;
	m_fTick = 0.0f;
	m_nTextureSizeChangeType = -1;
	memset(m_strName,0x00, sizeof(m_strName));
	m_nTextureNumber = 0;

	m_fEmitLifeTime = 0.0f;
	m_fParticleLifeTime = 0.0f;
	m_vPos = D3DXVECTOR3(0,0,0);
	m_vArea = D3DXVECTOR3(0,0,0);
	m_vDir = D3DXVECTOR3(0,0,0);

	m_bCreateRandom = TRUE;
	m_fCircleForce = 0.0f;
	m_fCreateDensity = 0.0f;
	m_fEmitRadius = 0.0f;
	m_fRotateAngle = 0.0f;
	m_fTextureAnimationTime = 0.0f;
	m_nEmitterType = 0;
	m_nTextureAnimationType = 0;
	m_nParticleType = 0;

	m_fCurrentEmitLifeTime = 0.0f;
	m_fCurrentDelayTime = 0.0f;

	m_fEmitAngle = 0.0f;

	memset(m_strTextureName,0x00, sizeof(m_strTextureName));

	m_bZbufferEnable = FALSE;
	m_nPersistence = 0;
	m_fColorChangeStartTime = 0;

	m_pParent = NULL;

	m_fCurrentTick = 0;
}

CParticleSystem::~CParticleSystem()
{
	vector<Effect*>::iterator iter = m_vecParticle.begin();
	while(iter != m_vecParticle.end())
	{
		CParticle* p = (CParticle*)(*iter);
		m_vecParticle.erase(iter);
		delete p;
		p = NULL;
	}
}

// by dhkwon, 030917
void CParticleSystem::SetTexture(char* strTexture, int index)
{
	strcpy(m_strTextureName[index], strTexture );
}

BOOL CParticleSystem::Tick(float fElapsedTime)
{
//	fElapsedTime = 0.3f;
	if(!m_bLoop)// 루프가 아닌경우
	{
		if(m_fCurrentEmitLifeTime < 0 && m_vecParticle.empty()) 
		{
			return FALSE;//dead, 파티클이 남아있으면 안된다.
		}
		m_fCurrentEmitLifeTime -= fElapsedTime;
		m_fCurrentTick -= fElapsedTime;
	} else if( m_fDelayTime > 0) { // 루프이면서 딜레이가 있는 경우
		if(m_fCurrentEmitLifeTime < 0 && m_vecParticle.empty()) 
		{
			m_fCurrentDelayTime -= fElapsedTime;
			if(m_fCurrentDelayTime>0)
			{
				return TRUE;
			} else 
			{
				m_fCurrentDelayTime = m_fDelayTime;	
				m_fCurrentEmitLifeTime = m_fEmitLifeTime;
			}
		}
		m_fCurrentEmitLifeTime -= fElapsedTime;
		m_fCurrentTick -= fElapsedTime;
	} else // 루프이면서 딜레이가 없는 경우
	{
		m_fCurrentTick -= fElapsedTime;
	}
	if(m_fCurrentTick<0)
	{
		// 생성
		if(m_fCurrentEmitLifeTime>0)
		{
			if(m_fTick==0)
				m_fCurrentEmitTime -= fElapsedTime;
			else
				m_fCurrentEmitTime -= m_fTick;//fElapsedTime;
			if(m_fCurrentEmitTime<0)
			{
				for(int i=0; i<m_nEmitMass; i++)
				{
					D3DXMATRIX mat;
					CParticle* p = new CParticle(m_nParticleType);
					p->m_pParent = this;
					p->m_fLifeTime = m_fParticleLifeTime;
					p->m_fSize = m_fTextureStartSize;
					p->m_cColor = m_cStartColor;
					p->m_cColorStep = m_cColorVel;
					p->m_fTextureSizeVel = m_fTextureSizeVel;
					switch(m_nEmitterType)
					{
					case EMITTER_POINT:
						{
							p->m_vPos = m_vPos;
						}
						break;
					case EMITTER_CIRCLE:
						{
							if(m_bCreateRandom)
							{
								p->m_vPos.x = m_vPos.x+Random(m_fEmitRadius, -m_fEmitRadius);
								p->m_vPos.y = m_vPos.y;
								p->m_vPos.z = m_vPos.z+Random(m_fEmitRadius, -m_fEmitRadius);
							} else {
								D3DXMATRIX	matTemp;
								D3DXVECTOR3 vTemp(0,1,0), vPos(m_fEmitRadius,0,0);
								D3DXMatrixRotationAxis( &matTemp, &vTemp, m_fEmitAngle*i );
								D3DXVec3TransformCoord( &p->m_vPos, &vPos, &matTemp );
								p->m_vPos += m_vPos;
							}

						}
						break;
					case EMITTER_SPHERE:
						{
//							if(m_bCreateRandom)
//							{
								p->m_vPos.x = m_vPos.x+Random(m_fEmitRadius, -m_fEmitRadius);
								p->m_vPos.y = m_vPos.y+Random(m_fEmitRadius, -m_fEmitRadius);
								p->m_vPos.z = m_vPos.z+Random(m_fEmitRadius, -m_fEmitRadius);
//							} else {
//								D3DXMATRIX	matTemp;
//								D3DXVECTOR3 vTemp(0,1,0), vPos(m_fEmitRadius,m_fEmitRadius,m_fEmitRadius);
//								D3DXMatrixRotationAxis( &matTemp, &vTemp, m_fCurrentEmitLifeTime*10 );
//								D3DXVec3TransformCoord( &p->m_vPos, &vPos, &matTemp );
//							}
						}
						break;
					case EMITTER_AREA:
						{
							p->m_vPos.x = Random(m_vPos.x, m_vArea.x);
							p->m_vPos.y = Random(m_vPos.y, m_vArea.y);
							p->m_vPos.z = Random(m_vPos.z, m_vArea.z);
						}
						break;
					}
					D3DXVECTOR3 pos;
					if(m_pParent)
					{
						// 실제 좌표 세팅
						pos = m_pParent->m_vPos;
						D3DXVec3TransformCoord( &pos, &pos, &m_pParent->m_pParent->m_mMatrix);
					}
					else 
					{
						pos = D3DXVECTOR3(0,0,0);
					}
					p->m_vPos += pos;
					p->m_vStartPos = pos;
					p->m_vVel = m_vVel;
					p->m_vDir = D3DXVECTOR3(m_vDir.x+Random(m_fCreateDensity,-m_fCreateDensity),
										    m_vDir.y+Random(m_fCreateDensity,-m_fCreateDensity),
											m_vDir.z+Random(m_fCreateDensity,-m_fCreateDensity));
					if(m_pParent->m_bUseCharacterMatrix)
					{
						D3DXMATRIX m = m_pParent->m_pParent->m_mMatrix;
						m._41 = 0;
						m._42 = 0;
						m._43 = 0;
						D3DXVec3TransformCoord( &p->m_vVel, &p->m_vVel, &m );
						D3DXVec3TransformCoord( &p->m_vDir, &p->m_vDir, &m );
					}
//					D3DXMatrixRotationAxis(&mat, m_vDir, Random(-m_fCreateDensity,m_fCreateDensity));
//					D3DXVec3TransformCoord(&(p->m_vDir), &m_vDir, &mat);
//					p->m_vArea = m_vArea;
					p->m_fCircleForce = m_fCircleForce;
//					p->m_fCreateDensity = m_fCreateDensity;
//					p->m_fEmitRadius = m_fEmitRadius;
					p->m_fGravity = m_fGravity;
					p->m_fRotateAngle = m_fRotateAngle;
					p->m_nTextureNumber = m_nTextureNumber;
					p->m_fTextureAnimationTime = m_fTextureAnimationTime;
					p->m_nTextureAnimationType = m_nTextureAnimationType;
					if(m_nTextureAnimationType == TEXTURE_ANIMATION_RANDOM)
						p->m_nTextureType = rand()%m_nTextureNumber;
					else
						p->m_nTextureType = 0;
					p->m_fTextureSizeMax = m_fTextureSizeMax;
					p->m_fTextureSizeMin = m_fTextureSizeMin;
					p->m_fTextureSizeMax = m_fTextureSizeMax;
					p->m_fTextureSizeMin = m_fTextureSizeMin;

					if(m_nTextureSizeChangeType == TEXTURE_SIZE_RANDOM)// 텍스쳐 사이즈
					{
						p->m_fSize = Random(m_fTextureSizeMax, m_fTextureSizeMin);
						p->m_fTextureStartSize = p->m_fSize;
					} else
					{
						p->m_fTextureStartSize = m_fTextureStartSize;
					}

					p->m_fTextureSizeVel = m_fTextureSizeVel;
					p->m_nTextureSizeChangeType = m_nTextureSizeChangeType;
					p->m_fColorChangeStartTime = m_fColorChangeStartTime;

					p->m_nPersistence = m_nPersistence;
					p->InitDeviceObjects();
					p->RestoreDeviceObjects();
					m_vecParticle.push_back((Effect*)p);
				}
				m_fCurrentEmitTime = m_fEmitTime;
			}
		} else {
			if(m_vecParticle.empty()) 
			{
				return FALSE;//dead, 파티클이 남아있으면 안된다.
			}

		}
		// 이동, 삭제
		vector<Effect*> vecParticle;
		vector<Effect*>::iterator iter = m_vecParticle.begin();
		while(iter != m_vecParticle.end())
		{
			float tick = m_fTick;
			if(tick == 0)
				tick = fElapsedTime;
			CParticle* pParticle=NULL;
			CParticle* p = (CParticle*)(*iter);
			// 잔상(persistence)
			if(m_nPersistence>0)
			{
				pParticle = new CParticle(m_nParticleType);
				memcpy(pParticle,p,sizeof(CParticle));
			}

			if(p->Tick(tick>fElapsedTime ? tick : fElapsedTime))
			{
				if(p->m_nPersistence>0)
				{
					p->m_nPersistence=0;
					pParticle->m_nPersistence--;
					D3DXCOLOR step(0.03f,0.03f,0.03f,0.03f);
					pParticle->m_cColor -= step;
					if(pParticle->m_cColor.r < 0 ) pParticle->m_cColor.r = 0;				
					if(pParticle->m_cColor.g < 0 ) pParticle->m_cColor.g = 0;				
					if(pParticle->m_cColor.b < 0 ) pParticle->m_cColor.b = 0;				
					if(pParticle->m_cColor.a < 0 ) pParticle->m_cColor.a = 0;				
					if(pParticle->m_cColor == 0 )
					{
						SAFE_DELETE(pParticle);
					} else
					{
						D3DXVECTOR3 vDir = p->m_vPos - pParticle->m_vPos ;
//						D3DXVECTOR3 vDir = pParticle->m_vPos - p->m_vPos;
						D3DXVec3Normalize( &vDir, &vDir );
						pParticle->m_vPos = p->m_vPos + vDir * pParticle->m_fSize/10;
						pParticle->InitDeviceObjects();
						pParticle->RestoreDeviceObjects();
						vecParticle.push_back((Effect*)pParticle);
					}
				} else
				{
					SAFE_DELETE(pParticle);
				}

				iter ++;
//				continue;			
			}
			else 
			{
				SAFE_DELETE(pParticle);
				m_vecParticle.erase(iter);
				p->InvalidateDeviceObjects();
				p->DeleteDeviceObjects();
				SAFE_DELETE(p);
			}
		}
		m_fCurrentTick = m_fTick;
		if(vecParticle.size()>0)
		{
			m_vecParticle.insert(m_vecParticle.end(), vecParticle.begin(), vecParticle.end());
		}
	}
	return TRUE;
}

void CParticleSystem::Render()
{

}

HRESULT CParticleSystem::InitDeviceObjects()
{
//	m_fCurrentEmitTime = m_fEmitTime; // 발산시스템 시간
//	m_fCurrentTick = m_fTick;	// Frame Rate
	m_fCurrentEmitLifeTime = m_fEmitLifeTime;

	
	return S_OK;
}

HRESULT CParticleSystem::RestoreDeviceObjects()
{
/*	g_pD3dDev->BeginStateBlock();
	g_pD3dDev->SetRenderState( D3DRS_ZENABLE, m_bZbufferEnable );
	g_pD3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	g_pD3dDev->SetRenderState( D3DRS_SRCBLEND, m_dwSrcBlend );
	g_pD3dDev->SetRenderState( D3DRS_DESTBLEND, m_dwDestBlend );
	g_pD3dDev->SetRenderState( D3DRS_LIGHTING, TRUE );
	g_pD3dDev->EndStateBlock( &m_dwStateBlock );
*/	return S_OK;
}

HRESULT CParticleSystem::InvalidateDeviceObjects()
{
//	g_pD3dDev->DeleteStateBlock( m_dwStateBlock );
	return S_OK;
}

HRESULT CParticleSystem::DeleteDeviceObjects()
{
	return S_OK;
}
