www.pudn.com > snow.rar > LensFlare.cpp


#include "LensFlare.h" 
 
CLensFlareSpot::CLensFlareSpot() 
{ 
	m_pTexture = NULL; 
	m_fSize = 1.0f; 
	m_fLinePos = 0.0f; 
  m_Color = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); 
} 
 
CLensFlareSpot::CLensFlareSpot(LPDIRECT3DTEXTURE9 pTex, float fSize,  
                               float fLinePos, D3DXCOLOR Color) 
{ 
	m_pTexture = pTex; 
	m_fSize = fSize; 
	m_fLinePos = fLinePos; 
  m_Color = Color; 
	 
} 
	 
CLensFlareSpot::~CLensFlareSpot() 
{ 
} 
 
CLensFlare::CLensFlare() 
{ 
	SetIntensity(CMinMax(0.0f, 1.0f)); 
	SetIntensityBorder(300); 
  m_pd3dDevice = NULL; 
} 
 
CLensFlare::~CLensFlare() 
{ 
  InvalidateDeviceObjects(); 
} 
 
HRESULT CLensFlare::RestoreDeviceObjects(LPDIRECT3DDEVICE9 pDev) 
{ 
	m_pd3dDevice = pDev; 
  m_pVBSpots = NULL; 
	m_iVBSize = 1; 
   
	return(RecreateVB()); 
} 
 
HRESULT CLensFlare::RecreateVB() 
{ 
	HRESULT hr = S_OK; 
   
	SAFE_RELEASE(m_pVBSpots); 
	 
	if (m_iVBSize) { 
		hr = m_pd3dDevice->CreateVertexBuffer(m_iVBSize*sizeof(VERTEX_LENSFLARE)*6, 
			0, D3DFVF_LENSFLARE, D3DPOOL_MANAGED, &m_pVBSpots,NULL); 
 
		if (FAILED(hr)) { 
			m_pVBSpots = NULL; 
		} 
	} 
  return hr; 
} 
 
void CLensFlare::InvalidateDeviceObjects() 
{ 
  DeleteTextures(); 
	DeleteSpots(); 
  SAFE_RELEASE(m_pVBSpots);    
} 
 
void CLensFlare::CalcLightSourceScreenCoords(Camera &m_camera, D3DXMATRIX matProj, 
												D3DXVECTOR3 vLightPos, int iScreenWidth, int iScreenHeight, 
												int &iCoordX, int &iCoordY, int &iCoordW) 
{ 
	D3DXMATRIX matWorld, matView, matConcat, matViewportScale; 
	D3DXVECTOR4 vResult; 
	 
	matViewportScale = D3DXMATRIX( 
	  iScreenWidth/2, 0, 0, 0, 
		0, -iScreenHeight/2, 0, 0, 
		0, 0, 1, 0, 
		iScreenWidth/2, iScreenHeight/2, 0, 1 
	); 
 
	m_camera.getViewMatrix(&matView); 
	D3DXMatrixIdentity(&matWorld); // no need for a world xform 
	matConcat = matWorld; 
	matConcat *= matView; 
	matConcat *= matProj; 
	matConcat *= matViewportScale; 
 
	D3DXVec3Transform(&vResult, &vLightPos, &matConcat); 
 
	iCoordX = vResult.x/vResult.w; 
	iCoordY = vResult.y/vResult.w; 
	iCoordW = vResult.w; 
} 
void CLensFlare::Render(Camera &m_camera, D3DXMATRIX matProj, 
												D3DXVECTOR3 vLightPos, int iScreenWidth,  
												int iScreenHeight, bool bFirstOnly) 
{ 
	int iScreenX, iScreenY, iScreenW; 
	CalcLightSourceScreenCoords(m_camera, matProj, vLightPos, iScreenWidth, iScreenHeight, 
		iScreenX, iScreenY, iScreenW); 
	 
	if (iScreenW >= 0.0f)  
		Render(iScreenX, iScreenY, iScreenWidth, iScreenHeight, bFirstOnly); 
} 
 
void CLensFlare::Render(int iLightSourceX, int iLightSourceY, int iScreenWidth,  
												int iScreenHeight, bool bFirstOnly) 
{ 
	// calculate actual intensity based on the given intensity and how far 
	// from the edge of the screen the sun is. 
	 
	float fRealIntensity; 
	int iAwayX = (iLightSourceX < 0) ? -iLightSourceX :  
	  (iLightSourceX > iScreenWidth) ? iLightSourceX-iScreenWidth : 0; 
	int iAwayY = (iLightSourceY < 0) ? -iLightSourceY :  
	  (iLightSourceY > iScreenHeight) ? iLightSourceY-iScreenHeight : 0; 
 
	float fAway = (iAwayX > iAwayY) ? iAwayX : iAwayY; 
 
	if (fAway > m_fIntensityBorder) fAway = m_fIntensityBorder; 
	 
	fRealIntensity = 1.0f - (fAway / m_fIntensityBorder); 
 
	fRealIntensity = m_fIntensity.m_Min + (fRealIntensity*(m_fIntensity.GetRange())); 
 
  // calculate spot positions and fill VB 
	{ 
	 
		int iCenterOfScreenX = iScreenWidth/2; 
		int iCenterOfScreenY = iScreenHeight/2; 
 
		int iDistanceX = iCenterOfScreenX - iLightSourceX; 
		int iDistanceY = iCenterOfScreenY - iLightSourceY; 
 
		// lock the vertex buffer 
		VERTEX_LENSFLARE *pVertices; 
   
		if(FAILED(m_pVBSpots->Lock( 0, m_iVBSize*6*sizeof(VERTEX_LENSFLARE), (VOID**)&pVertices, 0))) 
			return; 
 
		// for each spot in this flare... 
		for (std::vector::iterator i = m_Spots.begin(); i != m_Spots.end(); i++) { 
			CLensFlareSpot &spot = (*i); 
 
			// calculate this spot's center position 
			int iSpotCenterPosX = iCenterOfScreenX - ((float)iDistanceX * spot.GetLinePos()); 
			int iSpotCenterPosY = iCenterOfScreenY - ((float)iDistanceY * spot.GetLinePos()); 
			int iSizeDiv2 = (int)((float)iScreenWidth * spot.GetSize()/2.0f); 
 
			D3DXCOLOR color = spot.GetColor(); 
			color.a *= fRealIntensity; 
			if (color.a > 1.0f) color.a = 1.0f; 
			if (color.a < 0.0f) color.a = 0.0f; 
			if (bFirstOnly && i != m_Spots.begin()) color.a = 0.0f; 
 
			// first triangle 
			pVertices->color = color; 
			 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX-iSizeDiv2, iSpotCenterPosY-iSizeDiv2, 0); 
			pVertices->tu = 0.0f; pVertices->tv = 0.0f;	pVertices->rhw = 1.0f; 
			pVertices++; 
 
			pVertices->color = color; 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX+iSizeDiv2, iSpotCenterPosY-iSizeDiv2, 0); 
			pVertices->tu = 1.0f; pVertices->tv = 0.0f; pVertices->rhw = 1.0f; 
			pVertices++; 
 
			pVertices->color = color; 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX+iSizeDiv2, iSpotCenterPosY+iSizeDiv2, 0); 
			pVertices->tu = 1.0f; pVertices->tv = 1.0f; pVertices->rhw = 1.0f; 
			pVertices++; 
			 
 
			// second triangle 
			pVertices->color = color; 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX-iSizeDiv2, iSpotCenterPosY-iSizeDiv2, 0); 
			pVertices->tu = 0.0f; pVertices->tv = 0.0f; pVertices->rhw = 1.0f; 
			pVertices++; 
 
			pVertices->color = color; 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX+iSizeDiv2, iSpotCenterPosY+iSizeDiv2, 0); 
			pVertices->tu = 1.0f; pVertices->tv = 1.0f; pVertices->rhw = 1.0f; 
			pVertices++; 
 
			pVertices->color = color; 
			pVertices->position = D3DXVECTOR3(iSpotCenterPosX-iSizeDiv2, iSpotCenterPosY+iSizeDiv2, 0); 
			pVertices->tu = 0.0f; pVertices->tv = 1.0f; pVertices->rhw = 1.0f; 
			pVertices++; 
		} // next spot 
 
		// unlock VB 
		m_pVBSpots->Unlock(); 
	} 
 
	// render spots 
	{ 
		m_pd3dDevice->SetRenderState(D3DRS_LIGHTING,  FALSE ); 
		m_pd3dDevice->SetRenderState(D3DRS_CULLMODE,  D3DCULL_NONE ); 
   
		// turn on additive alpha blending 
		m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); 
		m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 
		m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); 
 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE); 
 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); 
		m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE); 
 
		// set custom vertex shader 
		m_pd3dDevice->SetStreamSource(0, m_pVBSpots, 0,sizeof(VERTEX_LENSFLARE)); 
      
		// this isn't the fastest way to do things, but it's easy to understand. 
		// optimization left as an exercise for the reader :) 
		for (int q=0; q < m_Spots.size(); q++) { 
			m_pd3dDevice->SetTexture(0, m_Spots[q].GetTexture()); 
			m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, q*6, 2); 
		} 
	} 
	 
} 
 
void CLensFlare::DeleteTextures() 
{ 
  for (std::vector::iterator i = m_Textures.begin();  
       i != m_Textures.end(); i++) { 
    SAFE_RELEASE((*i)); 
  } 
  m_Textures.clear(); 
} 
 
void CLensFlare::DeleteSpots() 
{ 
  m_Spots.clear(); 
	m_iVBSize = 0; 
	RecreateVB(); 
} 
 
LPDIRECT3DTEXTURE9 CLensFlare::AddTexture(const char *strFilename) 
{ 
  LPDIRECT3DTEXTURE9 pTexture = NULL; 
   
  // create this texture 
  if (FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,  
    strFilename, &pTexture))) { 
    return(NULL); 
  } 
   
  // add to vector 
  m_Textures.push_back(pTexture); 
  return(pTexture); 
} 
 
void CLensFlare::AddSpot(CLensFlareSpot &spot) 
{ 
  m_Spots.push_back(spot); 
	m_iVBSize = m_Spots.size(); 
	RecreateVB(); 
}