#include "Main.h"
ShadowMap::ShadowMap()
{
_DepthStencil = NULL;
}
ShadowMap::~ShadowMap()
{
FreeMemory();
}
void ShadowMap::FreeMemory()
{
for(UINT Index = 0; Index < ShadowMapCount; Index++)
{
_DepthMapTextures[Index].FreeMemory();
}
_DepthMapBlurTexture.FreeMemory();
if(_DepthStencil != NULL)
{
_DepthStencil->Release();
_DepthStencil = NULL;
}
_VShaderCreate.FreeMemory();
_PShaderCreate.FreeMemory();
_VShaderRender.FreeMemory();
_PShaderRender.FreeMemory();
_VShaderGaussian.FreeMemory();
_PShaderGaussianX.FreeMemory();
_PShaderGaussianY.FreeMemory();
}
void ShadowMap::SetAsRenderTarget(UINT ShadowMapIndex, IDirect3DDevice9 *Device)
{
_DepthMapTextures[ShadowMapIndex].SetAsRenderTarget(0);
Device->SetDepthStencilSurface(_DepthStencil);
Device->Clear( 0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 255, 0, 0), 1.0f, 0 );
_VShaderCreate.Set();
_PShaderCreate.Set();
}
void ShadowMap::SetAsTextures(IDirect3DDevice9 *Device)
{
for(UINT ShadowMapIndex = 0; ShadowMapIndex < ShadowMapCount; ShadowMapIndex++)
{
_DepthMapTextures[ShadowMapIndex].Set(ShadowMapIndex + 1);
}
_VShaderRender.Set();
_PShaderRender.Set();
}
void ShadowMap::SetCameraMatrices(const MatrixController &MC, ShadowMapShaderType Shader)
{
if(Shader == ShadowMapShaderCreate)
{
Matrix4 WorldView = MC.World * MC.View;
Matrix4 WorldViewProj = WorldView * MC.Perspective;
_VShaderCreate.SetMatrix("WorldView", WorldView);
_VShaderCreate.SetMatrix("WorldViewProj", WorldViewProj);
}
else if(Shader == ShadowMapShaderRender)
{
_VShaderRender.SetMatrix("World", MC.World);
_VShaderRender.SetMatrix("WorldViewProj", MC.TotalMatrix());
}
}
void ShadowMap::SetLightMatrices(UINT LightIndex, const Camera &LightCamera, const Matrix4 &Perspective)
{
Matrix4 View = LightCamera.Matrix();
Matrix4 ViewProj = View * Perspective;
_StringLightView[_StringLightView.Length() - 1] = '0' + LightIndex;
_StringLightViewProj[_StringLightViewProj.Length() - 1] = '0' + LightIndex;
_StringLightDir[_StringLightDir.Length() - 1] = '0' + LightIndex;
_VShaderRender.SetMatrix(_StringLightView.CString(), View);
_VShaderRender.SetMatrix(_StringLightViewProj.CString(), ViewProj);
_PShaderRender.SetVec3(_StringLightDir.CString(), LightCamera.VecLookDir());
if(LightIndex == 0)
{
_PShaderRender.SetVec3("LightPos", LightCamera.VecEye());
}
}
void ShadowMap::Init(D3D9GraphicsDevice &GD, UINT Resolution)
{
FreeMemory();
_StringLightDir = "LightDir0";
_StringLightView = "LightView0";
_StringLightViewProj = "LightViewProj0";
for(UINT Index = 0; Index < ShadowMapCount; Index++)
{
_DepthMapTextures[Index].Init(GD);
_DepthMapTextures[Index].Allocate(D3DFMT_G32R32F, Resolution, Resolution, true, 1);
}
_DepthMapBlurTexture.Init(GD);
_DepthMapBlurTexture.Allocate(D3DFMT_G32R32F, Resolution, Resolution, true, 1);
D3DAlwaysValidate( GD.GetDevice()->CreateDepthStencilSurface(Resolution, Resolution, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &_DepthStencil, NULL), "CreateDepthStencilSurface" );
_VShaderCreate.Init(GD, "Assets\\ShadowMapCreate.vs");
_PShaderCreate.Init(GD, "Assets\\ShadowMapCreate.ps");
_VShaderRender.Init(GD, "Assets\\ShadowMapRender.vs");
_PShaderRender.Init(GD, "Assets\\ShadowMapRender.ps");
_VShaderGaussian.Init(GD, "Assets\\GaussianBlur.vs");
_PShaderGaussianX.Init(GD, "Assets\\GaussianBlurX.ps");
_PShaderGaussianY.Init(GD, "Assets\\GaussianBlurY.ps");
_SimpleQuadMesh.SetGD(GD);
_SimpleQuadMesh.CreateCanonicalRenderPlane();
}
void LoadChannel(const Grid<Vec2f> &Input, Grid<float> &Output)
{
Output.Allocate(Input.Rows(), Input.Cols());
for(UINT Row = 0; Row < Input.Rows(); Row++)
{
for(UINT Col = 0; Col < Input.Cols(); Col++)
{
Output(Row, Col) = Input(Row, Col).x;
}
}
}
void ShadowMap::SaveTextureToFile(D3D9Texture &T, const String &Filename)
{
Grid<Vec2f> Data;
Grid<float> SingleChannel;
Bitmap Bmp;
T.ReadData(Data);
LoadChannel(Data, SingleChannel);
Bmp.LoadGrid(SingleChannel);
Bmp.SavePNG(Filename);
}
void ShadowMap::BlurAllShadowMaps(IDirect3DDevice9 *Device)
{
const bool DumpShadowMap = false;
const UINT DumpShadowMapIndex = 1;
D3D9ProtectRenderTarget Protector(Device, true, true);
if(DumpShadowMap)
{
SaveTextureToFile(_DepthMapTextures[DumpShadowMapIndex], "Input.png");
}
Device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
for(UINT Index = 0; Index < ShadowMapCount; Index++)
{
_DepthMapTextures[Index].Set(0);
_DepthMapBlurTexture.SetAsRenderTarget(0);
Device->SetDepthStencilSurface(_DepthStencil);
_VShaderGaussian.Set();
_PShaderGaussianX.Set();
_SimpleQuadMesh.Render();
if(DumpShadowMap && Index == DumpShadowMapIndex)
{
SaveTextureToFile(_DepthMapBlurTexture, "Intermediate.png");
}
_DepthMapTextures[Index].SetAsRenderTarget(0);
_DepthMapBlurTexture.Set(0);
_PShaderGaussianY.Set();
_SimpleQuadMesh.Render();
if(DumpShadowMap && Index == DumpShadowMapIndex)
{
SaveTextureToFile(_DepthMapTextures[DumpShadowMapIndex], "Output.png");
}
Device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
}
}
void ShadowMap::SaveDebugBitmap(const String &Filename)
{
Grid<float> Data;
Bitmap Bmp;
_DepthMapTextures[0].ReadData(Data);
Bmp.LoadGrid(Data);
Bmp.SavePNG(Filename);
}