#include "Main.h"
void StateManager::Dump(ofstream &DumpFile)
{
DumpFile << endl << "StateManager Dump\n";
DumpFile << "Texture memory:\t" << TextureMemorySize() << " bytes\n";
DumpFile << "Texture count:\t" << Textures.size() << endl;
}
void StateManager::Init()
{
NullTexture = new Texture(NULL);
CurVShader = NULL;
CurPShader = NULL;
CurIBuffer = NULL;
D3DSURFACE_DESC Desc;
Desc.Width = 1;
Desc.Height = 1;
Bitmap BlackBmp(1, 1);
BlackBmp.Clear();
NullTexture->Update(BlackBmp, Desc);
for(UINT i = 0; i < MaxTextures; i++)
{
CurTexture[i] = NullTexture;
}
for(UINT i = 0; i < MaxVShaderFloatConstants; i++)
{
VShaderFloatConstants[i] = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
}
for(UINT i = 0; i < MaxVShaderBoolConstants; i++)
{
VShaderBoolConstants[i] = FALSE;
}
for(UINT i = 0; i < MaxVShaderIntConstants; i++)
{
VShaderIntConstants[i] = Int4(0, 0, 0, 0);
}
VertexShaderSimulator.LoadConstantsFromDevice();
VertexShaderSimulator.ResetRegisters();
VertexShaderSimulator.InitalizeHashes();
for(UINT i = 0; i < MaxPShaderFloatConstants; i++)
{
PShaderFloatConstants[i] = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
}
for(UINT i = 0; i < MaxPShaderBoolConstants; i++)
{
PShaderBoolConstants[i] = FALSE;
}
for(UINT i = 0; i < MaxPShaderIntConstants; i++)
{
PShaderIntConstants[i] = Int4(0, 0, 0, 0);
}
}
UINT StateManager::TextureMemorySize()
{
UINT Total = 0;
TextureMap::const_iterator Iterator = Textures.begin();
while(Iterator != Textures.end())
{
Total += Iterator->second->Bmp().Width() * Iterator->second->Bmp().Height() * 4;
Iterator++;
}
return Total;
}
Texture* StateManager::UnlockTexture(D3DSURFACE_DESC &Desc, Bitmap &Bmp, HANDLE TextureHandle)
{
TextureMap::iterator Iterator = Textures.find(TextureHandle);
if(Iterator == Textures.end())
{
Texture *NewTexture = new Texture(TextureHandle);
NewTexture->Update(Bmp, Desc);
Textures[TextureHandle] = NewTexture;
return NewTexture;
}
else
{
Iterator->second->Update(Bmp, Desc);
return Iterator->second;
}
}
void StateManager::LockVBuffer(BufferLockData &Data, D3DVERTEXBUFFER_DESC &Desc)
{
VBufferMap::iterator Iterator = VBuffers.find(Data.Handle);
if(Iterator == VBuffers.end())
{
if(!Data.Create)
{
g_Context->Files.Assert << "VBuffer lock called before create\n";
}
VBuffer *NewBuffer = new VBuffer(Data.Handle);
NewBuffer->Update(Data, Desc);
VBuffers[Data.Handle] = NewBuffer;
}
else
{
if(Data.Create)
{
}
Iterator->second->Update(Data, Desc);
}
}
void StateManager::LockIBuffer(BufferLockData &Data, D3DINDEXBUFFER_DESC &Desc)
{
IBufferMap::iterator Iterator = IBuffers.find(Data.Handle);
if(Iterator == IBuffers.end())
{
if(!Data.Create)
{
g_Context->Files.Assert << "IBuffer lock called before create\n";
}
IBuffer *NewBuffer = new IBuffer(Data.Handle);
NewBuffer->Update(Data, Desc);
IBuffers[Data.Handle] = NewBuffer;
}
else
{
if(Data.Create)
{
}
Iterator->second->Update(Data, Desc);
}
}
bool StateManager::DestroyTexture(HANDLE Handle)
{
TextureMap::iterator Iterator = Textures.find(Handle);
if(Iterator == Textures.end())
{
return false;
}
else
{
for(UINT i = 0; i < MaxTextures; i++)
{
if(g_Context->Managers.State.CurTexture[i] == Iterator->second)
{
g_Context->Managers.State.CurTexture[i] = g_Context->Managers.State.NullTexture;
}
}
delete Iterator->second;
Textures.erase(Iterator);
return true;
}
}
bool StateManager::DestroyVBuffer(HANDLE Handle)
{
VBufferMap::iterator Iterator = VBuffers.find(Handle);
if(Iterator == VBuffers.end())
{
return false;
}
else
{
g_Context->Files.Assert << " Destroyed VBuffer: " << Handle << endl;
delete Iterator->second;
VBuffers.erase(Iterator);
return true;
}
}
bool StateManager::DestroyIBuffer(HANDLE Handle)
{
IBufferMap::iterator Iterator = IBuffers.find(Handle);
if(Iterator == IBuffers.end())
{
return false;
}
else
{
g_Context->Files.Assert << " Destroyed IBuffer: " << Handle << endl;
delete Iterator->second;
IBuffers.erase(Iterator);
return true;
}
}
void StateManager::SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix)
{
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "SetTransform ";
}
switch(State)
{
case D3DTS_WORLD:
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "World updated\n";
}
break;
case D3DTS_VIEW:
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "View\n";
}
break;
case D3DTS_PROJECTION:
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "Projection\n";
}
break;
case D3DTS_TEXTURE0:
case D3DTS_TEXTURE1:
case D3DTS_TEXTURE2:
case D3DTS_TEXTURE3:
case D3DTS_TEXTURE4:
case D3DTS_TEXTURE5:
case D3DTS_TEXTURE6:
case D3DTS_TEXTURE7:
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "Texture" << UINT(State) - UINT(D3DTS_TEXTURE0) << endl;
}
break;
default:
g_Context->Files.Assert << "Unknown Transform State: " << State << endl;
}
}
void StateManager::SetMaterial(CONST D3DMATERIAL9* pMaterial)
{
if(pMaterial == NULL)
{
g_Context->Files.Assert << "SetMaterial pMaterial is NULL\n";
}
else
{
if(g_ReportingEvents)
{
g_Context->Files.CurrentFrameAllEvents << "Material Hash: " << Hasher.Hash((const char *)pMaterial, sizeof(D3DMATERIAL9))
<< " Diffuse: " << pMaterial->Diffuse.r << ' ' << pMaterial->Diffuse.g << ' ' << pMaterial->Diffuse.b << ' ' << pMaterial->Diffuse.a << ' '
<< " Ambient: " << pMaterial->Ambient.r << ' ' << pMaterial->Ambient.g << ' ' << pMaterial->Ambient.b << ' ' << pMaterial->Ambient.a << ' '
<< " Specular: " << pMaterial->Specular.r << ' ' << pMaterial->Specular.g << ' ' << pMaterial->Specular.b << ' ' << pMaterial->Specular.a << ' '
<< " Emissive: " << pMaterial->Emissive.r << ' ' << pMaterial->Emissive.g << ' ' << pMaterial->Emissive.b << ' ' << pMaterial->Emissive.a << endl;
}
CurMaterial = *pMaterial;
}
}
void StateManager::SetLight(UINT Index, CONST D3DLIGHT9* pLight)
{
if(Index < MaxLights)
{
CurLight[Index] = *pLight;
}
else
{
g_Context->Files.Assert << "SetLight Index > MaxLights\n";
}
}
void StateManager::SetViewport(CONST D3DVIEWPORT9* pViewport)
{
CurViewport = *pViewport;
}
void StateManager::SetTexture(DWORD Stage, HANDLE *SurfaceHandles, UINT HandleCount)
{
if(Stage >= MaxTextures && SurfaceHandles[0] != NULL)
{
g_Context->Files.Assert << "SetTexture Stage >= MaxTextures (" << Stage << ")\n";
return;
}
if(SurfaceHandles[0] == NULL)
{
CurTexture[Stage] = NullTexture;
return;
}
TextureMap::const_iterator TMapIterator;
TMapIterator = Textures.find(SurfaceHandles[0]);
if(TMapIterator == Textures.end())
{
CurTexture[Stage] = NullTexture;
g_Context->Files.Assert << "SetTexture TopLevelSurfaceHandle not in list: " << SurfaceHandles[0] << endl;
}
else
{
CurTexture[Stage] = TMapIterator->second;
if(g_ReportingEvents)
{
if(CurTexture[Stage]->ID().Length() == 0)
{
g_Context->Files.CurrentFrameAllEvents << "Texture unmatched\n";
}
else
{
g_Context->Files.CurrentFrameAllEvents << "Texture Name: " << CurTexture[Stage]->ID() << endl;
}
}
}
}
void StateManager::SetStreamSource(UINT StreamNumber, HANDLE VBufferHandle, UINT OffsetInBytes, UINT Stride)
{
if(VBufferHandle == NULL)
{
g_Context->Files.Assert << "SetStreamSource VBufferHandle NULL\n";
}
else if(VBuffers.find(VBufferHandle) == VBuffers.end())
{
g_Context->Files.Assert << "SetStreamSource VBufferHandle not in list: " << VBufferHandle << endl;
}
else if(StreamNumber >= MaxStreams)
{
g_Context->Files.Assert << "StreamNumber >= MaxStreams\n";
}
else
{
VBufferStreams[StreamNumber] = StreamInfo(VBuffers[VBufferHandle], OffsetInBytes, Stride);
}
}
void StateManager::SetIndices(HANDLE IBufferHandle)
{
if(IBufferHandle == NULL)
{
CurIBuffer = NULL;
}
else if(IBuffers.find(IBufferHandle) == IBuffers.end())
{
g_Context->Files.Assert << "SetIndices IBufferHandle not in list\n";
}
else
{
CurIBuffer = IBuffers[IBufferHandle];
}
}
void StateManager::SetVertexDeclaration(D3DVERTEXELEMENT9 *Elements, UINT ElementCount)
{
VertexDeclaration.ReSize(ElementCount - 1);
for(UINT i = 0; i < VertexDeclaration.Length(); i++)
{
VertexDeclaration[i] = Elements[i];
}
}
void StateManager::LoadVertexTexCoord0(Vec2f &TexCoord, UINT Index)
{
for(UINT i = 0; i < VertexDeclaration.Length(); i++)
{
const D3D9Base::D3DVERTEXELEMENT9 &Decl = VertexDeclaration[i];
if(Decl.Usage == D3DDECLUSAGE_TEXCOORD && Decl.UsageIndex == 0)
{
StreamInfo &Stream = VBufferStreams[Decl.Stream];
Assert(Stream.StreamData != NULL, "Reference to unbound stream");
BYTE *ByteStream = (BYTE *)(Stream.StreamData->Buffer.CArray() + Stream.OffsetInBytes + Index * Stream.Stride + Decl.Offset);
float *FloatStream = (float *)ByteStream;
Vec4f Result = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
switch(Decl.Type)
{
case D3DDECLTYPE_FLOAT1:
Result = Vec4f(FloatStream[0], 0.0f, 0.0f, 1.0f);
break;
case D3DDECLTYPE_FLOAT2:
Result = Vec4f(FloatStream[0], FloatStream[1], 0.0f, 1.0f);
break;
case D3DDECLTYPE_FLOAT3:
Result = Vec4f(FloatStream[0], FloatStream[1], FloatStream[2], 1.0f);
break;
case D3DDECLTYPE_FLOAT4:
Result = Vec4f(FloatStream[0], FloatStream[1], FloatStream[2], FloatStream[3]);
break;
default:
SignalError(String("Unsupported type: ") + String(UINT(Decl.Type)));
}
Assert(Decl.UsageIndex < MaxTexCoords, "Texture coordinate index out of range");
TexCoord = Vec2f(Result.x, Result.y);
return;
}
}
}
void StateManager::LoadVertexColor(RGBColor &C, UINT Index)
{
for(UINT i = 0; i < VertexDeclaration.Length(); i++)
{
const D3D9Base::D3DVERTEXELEMENT9 &Decl = VertexDeclaration[i];
if(Decl.Usage == D3DDECLUSAGE_COLOR && Decl.UsageIndex == 0)
{
StreamInfo &Stream = VBufferStreams[Decl.Stream];
Assert(Stream.StreamData != NULL, "Reference to unbound stream");
BYTE *ByteStream = (BYTE *)(Stream.StreamData->Buffer.CArray() + Stream.OffsetInBytes + Index * Stream.Stride + Decl.Offset);
float *FloatStream = (float *)ByteStream;
Vec4f Result = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
if(Decl.Type == D3DDECLTYPE_D3DCOLOR)
{
C = RGBColor(ByteStream[0], ByteStream[1], ByteStream[2], ByteStream[3]);
return;
}
else
{
SignalError(String("Unsupported type: ") + String(UINT(Decl.Type)));
}
}
}
}
void StateManager::LoadVertexData(VertexData &V, UINT Index)
{
for(UINT i = 0; i < VertexDeclaration.Length(); i++)
{
const D3D9Base::D3DVERTEXELEMENT9 &Decl = VertexDeclaration[i];
StreamInfo &Stream = VBufferStreams[Decl.Stream];
Assert(Stream.StreamData != NULL, "Reference to unbound stream");
const BYTE *ByteStream = (BYTE *)(Stream.StreamData->Buffer.CArray() + Stream.OffsetInBytes + Index * Stream.Stride + Decl.Offset);
const float *FloatStream = (float *)ByteStream;
const SHORT *ShortStream = (SHORT *)ByteStream;
Vec4f Result = Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
switch(Decl.Type)
{
case D3DDECLTYPE_FLOAT1:
Result = Vec4f(FloatStream[0], 0.0f, 0.0f, 1.0f);
break;
case D3DDECLTYPE_FLOAT2:
Result = Vec4f(FloatStream[0], FloatStream[1], 0.0f, 1.0f);
break;
case D3DDECLTYPE_FLOAT3:
Result = Vec4f(FloatStream[0], FloatStream[1], FloatStream[2], 1.0f);
break;
case D3DDECLTYPE_FLOAT4:
Result = Vec4f(FloatStream[0], FloatStream[1], FloatStream[2], FloatStream[3]);
break;
case D3DDECLTYPE_D3DCOLOR:
Result = Vec4f(float(ByteStream[0]) / 255.0f, float(ByteStream[1]) / 255.0f, float(ByteStream[2]) / 255.0f, float(ByteStream[3]) / 255.0f);
break;
case D3DDECLTYPE_UBYTE4N:
Result = Vec4f(float(ByteStream[0]) / 255.0f, float(ByteStream[1]) / 255.0f, float(ByteStream[2]) / 255.0f, float(ByteStream[3]) / 255.0f);
break;
case D3DDECLTYPE_UBYTE4:
Result = Vec4f(float(ByteStream[0]), float(ByteStream[1]), float(ByteStream[2]), float(ByteStream[3]));
break;
case D3DDECLTYPE_SHORT2:
Result = Vec4f(float(ShortStream[0]), float(ShortStream[1]), 0.0f, 1.0f);
break;
case D3DDECLTYPE_SHORT4:
Result = Vec4f(float(ShortStream[0]), float(ShortStream[1]), float(ShortStream[2]), float(ShortStream[3]));
break;
case D3DDECLTYPE_FLOAT16_2:
Result = Vec4f(float(ShortStream[0]), float(ShortStream[1]), 0.0f, 1.0f);
break;
case D3DDECLTYPE_FLOAT16_4:
Result = Vec4f(float(ShortStream[0]), float(ShortStream[1]), float(ShortStream[2]), float(ShortStream[3]));
break;
default:
SignalError(String("Unsupported type: ") + String(UINT(Decl.Type)));
}
if(Decl.Usage == D3DDECLUSAGE_POSITION)
{
V.Position = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_BLENDWEIGHT)
{
V.BlendWeight = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_BLENDINDICES)
{
V.BlendIndices = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_NORMAL)
{
V.Normal = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_BINORMAL)
{
V.BiNormal = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_TANGENT)
{
V.Tangent = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_COLOR)
{
Assert(Decl.UsageIndex < MaxColorCoords, "Color coordinate index out of range");
V.Color[Decl.UsageIndex] = Result;
}
else if(Decl.Usage == D3DDECLUSAGE_TEXCOORD)
{
Assert(Decl.UsageIndex < MaxTexCoords, "Texture coordinate index out of range");
V.TexCoord[Decl.UsageIndex] = Result;
}
}
}
void StateManager::SetFVF(DWORD NewFVF)
{
}
void StateManager::CreateVertexShader(CONST DWORD* pFunction, HANDLE Shader)
{
VShaderMap::iterator Iterator = VShaders.find(Shader);
if(Iterator == VShaders.end())
{
VShader *NewShader = new VShader(pFunction, Shader);
Assert(NewShader != NULL, "Out of memory in StateManager::CreateVertexShader");
if(CaptureAllShaders && !VertexShaderSimulator.ContainsHash(NewShader->Hash()))
{
String AssemblyFilename = g_Context->Parameters.ShaderCaptureDirectory + String("VShader") + String::ZeroPad(String(NewShader->Hash()), 10) + ".txt";
String SourceFilename = g_Context->Parameters.ShaderCaptureDirectory + String("VShader") + String::ZeroPad(String(NewShader->Hash()), 10) + ".cpp";
String HeaderFilename = g_Context->Parameters.ShaderCaptureDirectory + String("VShader") + String::ZeroPad(String(NewShader->Hash()), 10) + ".h";
ofstream AssemblyFile(AssemblyFilename.CString());
NewShader->OutputDisassembly(AssemblyFile);
if(g_Context->Parameters.OutputCSource)
{
ofstream SourceFile(SourceFilename.CString());
ofstream HeaderFile(HeaderFilename.CString());
NewShader->OutputCSource(SourceFile, HeaderFile);
}
}
VShaders[Shader] = NewShader;
}
else
{
}
}
void StateManager::CreatePixelShader(CONST DWORD* pFunction, HANDLE Shader)
{
PShaderMap::iterator Iterator = PShaders.find(Shader);
if(Iterator == PShaders.end())
{
PShader *NewShader = new PShader(pFunction, Shader);
Assert(NewShader != NULL, "Out of memory in StateManager::CreatePixelShader");
if(CaptureAllShaders)
{
VShader TempShader(pFunction, NULL);
String AssemblyFilename = String(g_Context->Parameters.ShaderCaptureDirectory) + String("PShader") + String::ZeroPad(String(TempShader.Hash()), 10) + ".txt";
ofstream DisassemblyFile(AssemblyFilename.CString());
TempShader.OutputDisassembly(DisassemblyFile);
}
PShaders[Shader] = NewShader;
}
else
{
}
}
void StateManager::SetVertexShader(HANDLE Shader)
{
if(Shader == NULL)
{
CurVShader = NULL;
}
else if(VShaders.find(Shader) == VShaders.end())
{
g_Context->Files.Assert << "SetVertexShader handle not in list\n";
}
else
{
CurVShader = VShaders[Shader];
}
}
void StateManager::SetPixelShader(HANDLE Shader)
{
if(Shader == NULL)
{
CurPShader = NULL;
}
else if(PShaders.find(Shader) == PShaders.end())
{
g_Context->Files.Assert << "SetPixelShader handle not in list\n";
}
else
{
CurPShader = PShaders[Shader];
}
}