📄 ch22p1_lensflare.cpp
字号:
#include "Ch22p1_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(LPDIRECT3DTEXTURE8 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<float>(0.0f, 1.0f));
SetIntensityBorder(300);
m_pd3dDevice = NULL;
}
CLensFlare::~CLensFlare()
{
InvalidateDeviceObjects();
}
HRESULT CLensFlare::RestoreDeviceObjects(LPDIRECT3DDEVICE8 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);
if (FAILED(hr)) {
m_pVBSpots = NULL;
}
}
return hr;
}
void CLensFlare::InvalidateDeviceObjects()
{
DeleteTextures();
DeleteSpots();
SAFE_RELEASE(m_pVBSpots);
}
void CLensFlare::CalcLightSourceScreenCoords(CCamera &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
);
matView = camera.GetViewMatrix();
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(CCamera &camera, D3DXMATRIX matProj,
D3DXVECTOR3 vLightPos, int iScreenWidth,
int iScreenHeight, bool bFirstOnly)
{
int iScreenX, iScreenY, iScreenW;
CalcLightSourceScreenCoords(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), (BYTE**)&pVertices, 0)))
return;
// for each spot in this flare...
for (std::vector<CLensFlareSpot>::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, sizeof(VERTEX_LENSFLARE));
m_pd3dDevice->SetVertexShader(D3DFVF_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<LPDIRECT3DTEXTURE8>::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();
}
LPDIRECT3DTEXTURE8 CLensFlare::AddTexture(const char *strFilename)
{
LPDIRECT3DTEXTURE8 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();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -