Add back the D3D9 code from before the April 2014 code dump.

Bug 22533227

Change-Id: Ib669fcd6a644c79b3a9e8f5dcf7da278d75cefef
Reviewed-on: https://swiftshader-review.googlesource.com/3730
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/D3D9/Direct3DStateBlock9.cpp b/src/D3D9/Direct3DStateBlock9.cpp
new file mode 100644
index 0000000..9c5d02a
--- /dev/null
+++ b/src/D3D9/Direct3DStateBlock9.cpp
@@ -0,0 +1,1342 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2011 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "Direct3DStateBlock9.hpp"
+
+#include "Direct3DDevice9.hpp"
+#include "Direct3DVertexDeclaration9.hpp"
+#include "Direct3DIndexBuffer9.hpp"
+#include "Direct3DVertexBuffer9.hpp"
+#include "Direct3DBaseTexture9.hpp"
+#include "Direct3DPixelShader9.hpp"
+#include "Direct3DVertexShader9.hpp"
+#include "Debug.hpp"
+
+#include <assert.h>
+
+namespace D3D9
+{
+	Direct3DStateBlock9::Direct3DStateBlock9(Direct3DDevice9 *device, D3DSTATEBLOCKTYPE type) : device(device), type(type)
+	{
+		vertexDeclaration = 0;
+
+		indexBuffer = 0;
+
+		for(int stream = 0; stream < 16; stream++)
+		{
+			streamSource[stream].vertexBuffer = 0;
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			texture[sampler] = 0;
+		}
+
+		pixelShader = 0;
+		vertexShader = 0;
+
+		clear();
+
+		if(type == D3DSBT_PIXELSTATE || type == D3DSBT_ALL)
+		{
+			capturePixelRenderStates();
+			capturePixelTextureStates();
+			capturePixelSamplerStates();
+			capturePixelShaderStates();
+		}
+		
+		if(type == D3DSBT_VERTEXSTATE || type == D3DSBT_ALL)
+		{
+			captureVertexRenderStates();
+			captureVertexSamplerStates();
+			captureVertexTextureStates();
+			captureNPatchMode();
+			captureLightStates();
+			captureVertexShaderStates();
+			captureStreamSourceFrequencies();
+			captureFVF();
+			captureVertexDeclaration();
+		}
+
+		if(type == D3DSBT_ALL)   // Capture remaining states
+		{
+			captureTextures();
+			captureTexturePalette();
+			captureVertexStreams();
+			captureIndexBuffer();
+			captureViewport();
+			captureScissorRectangle();
+			captureTransforms();
+			captureTextureTransforms();
+			captureClippingPlanes();
+			captureMaterial();
+		}
+	}
+
+	Direct3DStateBlock9::~Direct3DStateBlock9()
+	{
+		clear();
+	}
+
+	long Direct3DStateBlock9::QueryInterface(const IID &iid, void **object)
+	{
+		CriticalSection cs(device);
+
+		TRACE("");
+
+		if(iid == IID_IDirect3DStateBlock9 ||
+		   iid == IID_IUnknown)
+		{
+			AddRef();
+			*object = this;
+
+			return S_OK;
+		}
+
+		*object = 0;
+
+		return NOINTERFACE(iid);
+	}
+
+	unsigned long Direct3DStateBlock9::AddRef()
+	{
+		TRACE("");
+
+		return Unknown::AddRef();
+	}
+	
+	unsigned long Direct3DStateBlock9::Release()
+	{
+		TRACE("");
+
+		return Unknown::Release();
+	}
+
+	long Direct3DStateBlock9::Apply()
+	{
+		CriticalSection cs(device);
+
+		TRACE("");
+
+		if(device->isRecording())
+		{
+			return INVALIDCALL();
+		}
+		
+		if(fvfCaptured)
+		{
+			device->SetFVF(FVF);
+		}
+
+		if(vertexDeclarationCaptured)
+		{
+			device->SetVertexDeclaration(vertexDeclaration);
+		}
+
+		if(indexBufferCaptured)
+		{
+			device->SetIndices(indexBuffer);
+		}
+
+		for(int state = D3DRS_ZENABLE; state <= D3DRS_BLENDOPALPHA; state++)
+		{
+			if(renderStateCaptured[state])
+			{
+				device->SetRenderState((D3DRENDERSTATETYPE)state, renderState[state]);
+			}
+		}
+
+		if(nPatchModeCaptured)
+		{
+			device->SetNPatchMode(nPatchMode);
+		}
+
+		for(int stage = 0; stage < 8; stage++)
+		{
+			for(int state = D3DTSS_COLOROP; state <= D3DTSS_CONSTANT; state++)
+			{
+				if(textureStageStateCaptured[stage][state])
+				{
+					device->SetTextureStageState(stage, (D3DTEXTURESTAGESTATETYPE)state, textureStageState[stage][state]);
+				}
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			for(int state = D3DSAMP_ADDRESSU; state <= D3DSAMP_DMAPOFFSET; state++)
+			{
+				if(samplerStateCaptured[sampler][state])
+				{
+					int index = sampler < 16 ? sampler : D3DVERTEXTEXTURESAMPLER0 + (sampler - 16);
+					device->SetSamplerState(index, (D3DSAMPLERSTATETYPE)state, samplerState[sampler][state]);
+				}
+			}
+		}
+
+		for(int stream = 0; stream < 16; stream++)
+		{
+			if(streamSourceCaptured[stream])
+			{
+				device->SetStreamSource(stream, streamSource[stream].vertexBuffer, streamSource[stream].offset, streamSource[stream].stride);
+			}
+
+			if(streamSourceFrequencyCaptured[stream])
+			{
+				device->SetStreamSourceFreq(stream, streamSourceFrequency[stream]);
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			if(textureCaptured[sampler])
+			{
+				int index = sampler < 16 ? sampler : D3DVERTEXTEXTURESAMPLER0 + (sampler - 16);
+				device->SetTexture(index, texture[sampler]);
+			}
+		}
+
+		for(int state = 0; state < 512; state++)
+		{
+			if(transformCaptured[state])
+			{
+				device->SetTransform((D3DTRANSFORMSTATETYPE)state, &transform[state]);
+			}
+		}
+
+		if(materialCaptured)
+		{
+			device->SetMaterial(&material);
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			if(lightCaptured[index])
+			{
+				device->SetLight(index, &light[index]);
+			}
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			if(lightEnableCaptured[index])
+			{
+				device->LightEnable(index, lightEnableState[index]);
+			}
+		}
+
+		if(pixelShaderCaptured)
+		{
+			device->SetPixelShader(pixelShader);
+		}
+
+		if(vertexShaderCaptured)
+		{
+			device->SetVertexShader(vertexShader);
+		}
+
+		if(viewportCaptured)
+		{
+			device->SetViewport(&viewport);
+		}
+
+		for(int i = 0; i < 224; i++)
+		{
+			if(*(int*)pixelShaderConstantF[i] != 0x80000000)
+			{
+				device->SetPixelShaderConstantF(i, pixelShaderConstantF[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(pixelShaderConstantI[i][0] != 0x80000000)
+			{
+				device->SetPixelShaderConstantI(i, pixelShaderConstantI[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(pixelShaderConstantB[i] != 0x80000000)
+			{
+				device->SetPixelShaderConstantB(i, &pixelShaderConstantB[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 256; i++)
+		{
+			if(*(int*)vertexShaderConstantF[i] != 0x80000000)
+			{
+				device->SetVertexShaderConstantF(i, vertexShaderConstantF[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(vertexShaderConstantI[i][0] != 0x80000000)
+			{
+				device->SetVertexShaderConstantI(i, vertexShaderConstantI[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(vertexShaderConstantB[i] != 0x80000000)
+			{
+				device->SetVertexShaderConstantB(i, &vertexShaderConstantB[i], 1);
+			}
+		}
+
+		for(int index = 0; index < 6; index++)
+		{
+			if(clipPlaneCaptured[index])
+			{
+				device->SetClipPlane(index, clipPlane[index]);
+			}
+		}
+
+		if(scissorRectCaptured)
+		{
+			device->SetScissorRect(&scissorRect);
+		}
+
+		if(paletteNumberCaptured)
+		{
+			device->SetCurrentTexturePalette(paletteNumber);
+		}
+
+		return D3D_OK;
+	}
+
+	long Direct3DStateBlock9::Capture()
+	{
+		CriticalSection cs(device);
+
+		TRACE("");
+		
+		if(fvfCaptured)
+		{
+			device->GetFVF(&FVF);
+		}
+
+		if(vertexDeclarationCaptured)
+		{
+			Direct3DVertexDeclaration9 *vertexDeclaration;
+			device->GetVertexDeclaration(reinterpret_cast<IDirect3DVertexDeclaration9**>(&vertexDeclaration));
+			
+			if(vertexDeclaration)
+			{
+				vertexDeclaration->bind();
+				vertexDeclaration->Release();
+			}
+
+			if(this->vertexDeclaration)
+			{
+				this->vertexDeclaration->unbind();
+			}
+
+			this->vertexDeclaration = vertexDeclaration;
+		}
+
+		if(indexBufferCaptured)
+		{
+			Direct3DIndexBuffer9 *indexBuffer;
+			device->GetIndices(reinterpret_cast<IDirect3DIndexBuffer9**>(&indexBuffer));
+			
+			if(indexBuffer)
+			{
+				indexBuffer->bind();
+				indexBuffer->Release();
+			}
+
+			if(this->indexBuffer)
+			{
+				this->indexBuffer->unbind();
+			}
+
+			this->indexBuffer = indexBuffer;
+		}
+
+		for(int state = 0; state < D3DRS_BLENDOPALPHA + 1; state++)
+		{
+			if(renderStateCaptured[state])
+			{
+				device->GetRenderState((D3DRENDERSTATETYPE)state, &renderState[state]);
+			}
+		}
+
+		if(nPatchModeCaptured)
+		{
+			nPatchMode = device->GetNPatchMode();
+		}
+
+		for(int stage = 0; stage < 8; stage++)
+		{
+			for(int state = 0; state < D3DTSS_CONSTANT + 1; state++)
+			{
+				if(textureStageStateCaptured[stage][state])
+				{
+					device->GetTextureStageState(stage, (D3DTEXTURESTAGESTATETYPE)state, &textureStageState[stage][state]);
+				}
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			for(int state = 0; state < D3DSAMP_DMAPOFFSET + 1; state++)
+			{
+				if(samplerStateCaptured[sampler][state])
+				{
+					int index = sampler < 16 ? sampler : D3DVERTEXTEXTURESAMPLER0 + (sampler - 16);
+					device->GetSamplerState(index, (D3DSAMPLERSTATETYPE)state, &samplerState[sampler][state]);
+				}
+			}
+		}
+
+		for(int stream = 0; stream < 16; stream++)
+		{
+			if(streamSourceCaptured[stream])
+			{
+				Direct3DVertexBuffer9 *vertexBuffer;
+				device->GetStreamSource(stream, reinterpret_cast<IDirect3DVertexBuffer9**>(&vertexBuffer), &streamSource[stream].offset, &streamSource[stream].stride);
+
+				if(vertexBuffer)
+				{
+					vertexBuffer->bind();
+					vertexBuffer->Release();
+				}
+
+				if(streamSource[stream].vertexBuffer)
+				{
+					streamSource[stream].vertexBuffer->unbind();
+				}
+
+				streamSource[stream].vertexBuffer = vertexBuffer;
+			}
+
+			if(streamSourceFrequencyCaptured[stream])
+			{
+				device->GetStreamSourceFreq(stream, &streamSourceFrequency[stream]);
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			if(textureCaptured[sampler])
+			{
+				Direct3DBaseTexture9 *texture;
+				int index = sampler < 16 ? sampler : D3DVERTEXTEXTURESAMPLER0 + (sampler - 16);
+				device->GetTexture(index, reinterpret_cast<IDirect3DBaseTexture9**>(&texture));
+
+				if(texture)
+				{
+					texture->bind();
+					texture->Release();
+				}
+
+				if(this->texture[sampler])
+				{
+					this->texture[sampler]->unbind();
+				}
+
+				this->texture[sampler] = texture;
+			}
+		}
+
+		for(int state = 0; state < 512; state++)
+		{
+			if(transformCaptured[state])
+			{
+				device->GetTransform((D3DTRANSFORMSTATETYPE)state, &transform[state]);
+			}
+		}
+
+		if(materialCaptured)
+		{
+			device->GetMaterial(&material);
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			if(lightCaptured[index])
+			{
+				device->GetLight(index, &light[index]);
+			}
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			if(lightEnableCaptured[index])
+			{
+				lightEnableState[index] = false;
+				device->GetLightEnable(index, &lightEnableState[index]);
+			}
+		}
+
+		if(pixelShaderCaptured)
+		{
+			Direct3DPixelShader9 *pixelShader;
+			device->GetPixelShader(reinterpret_cast<IDirect3DPixelShader9**>(&pixelShader));
+
+			if(pixelShader)
+			{
+				pixelShader->bind();
+				pixelShader->Release();
+			}
+
+			if(this->pixelShader)
+			{
+				this->pixelShader->unbind();
+			}
+
+			this->pixelShader = pixelShader;
+		}
+
+		if(vertexShaderCaptured)
+		{
+			Direct3DVertexShader9 *vertexShader;
+			device->GetVertexShader(reinterpret_cast<IDirect3DVertexShader9**>(&vertexShader));
+
+			if(vertexShader)
+			{
+				vertexShader->bind();
+				vertexShader->Release();
+			}
+
+			if(this->vertexShader)
+			{
+				this->vertexShader->unbind();
+			}
+
+			this->vertexShader = vertexShader;
+		}
+
+		if(viewportCaptured)
+		{
+			device->GetViewport(&viewport);
+		}
+
+		for(int i = 0; i < 224; i++)
+		{
+			if(*(int*)pixelShaderConstantF[i] != 0x80000000)
+			{
+				device->GetPixelShaderConstantF(i, pixelShaderConstantF[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(pixelShaderConstantI[i][0] != 0x80000000)
+			{
+				device->GetPixelShaderConstantI(i, pixelShaderConstantI[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(pixelShaderConstantB[i] != 0x80000000)
+			{
+				device->GetPixelShaderConstantB(i, &pixelShaderConstantB[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 256; i++)
+		{
+			if(*(int*)vertexShaderConstantF[i] != 0x80000000)
+			{
+				device->GetVertexShaderConstantF(i, vertexShaderConstantF[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(vertexShaderConstantI[i][0] != 0x80000000)
+			{
+				device->GetVertexShaderConstantI(i, vertexShaderConstantI[i], 1);
+			}
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			if(vertexShaderConstantB[i] != 0x80000000)
+			{
+				device->GetVertexShaderConstantB(i, &vertexShaderConstantB[i], 1);
+			}
+		}
+
+		for(int index = 0; index < 6; index++)
+		{
+			if(clipPlaneCaptured[index])
+			{
+				device->GetClipPlane(index, clipPlane[index]);
+			}
+		}
+
+		if(scissorRectCaptured)
+		{
+			device->GetScissorRect(&scissorRect);
+		}
+
+		if(paletteNumberCaptured)
+		{
+			device->GetCurrentTexturePalette(&paletteNumber);
+		}
+
+		return D3D_OK;
+	}
+
+	long Direct3DStateBlock9::GetDevice(IDirect3DDevice9 **device)
+	{
+		CriticalSection cs(this->device);
+
+		TRACE("");
+
+		if(!device)
+		{
+			return INVALIDCALL();
+		}
+
+		this->device->AddRef();
+		*device = this->device;
+
+		return D3D_OK;
+	}
+
+	void Direct3DStateBlock9::lightEnable(unsigned long index, int enable)
+	{
+		if(index < 8)
+		{
+			lightEnableCaptured[index] = true;
+			lightEnableState[index] = enable;
+		}
+		else ASSERT(false);   // FIXME: Support unlimited index
+	}
+
+	void Direct3DStateBlock9::setClipPlane(unsigned long index, const float *plane)
+	{
+		clipPlaneCaptured[index] = true;
+		clipPlane[index][0] = plane[0];
+		clipPlane[index][1] = plane[1];
+		clipPlane[index][2] = plane[2];
+		clipPlane[index][3] = plane[3];
+	}
+
+	void Direct3DStateBlock9::setCurrentTexturePalette(unsigned int paletteNumber)
+	{
+		paletteNumberCaptured = true;
+		this->paletteNumber = paletteNumber;
+	}
+
+	void Direct3DStateBlock9::setFVF(unsigned long FVF)
+	{
+		fvfCaptured = true;
+		this->FVF = FVF;
+	}
+
+	void Direct3DStateBlock9::setIndices(Direct3DIndexBuffer9 *indexBuffer)
+	{
+		if(indexBuffer) indexBuffer->bind();
+		if(this->indexBuffer) this->indexBuffer->unbind();
+
+		indexBufferCaptured = true;
+		this->indexBuffer = indexBuffer;
+	}
+
+	void Direct3DStateBlock9::setLight(unsigned long index, const D3DLIGHT9 *light)
+	{
+		if(index < 8)
+		{
+			lightCaptured[index] = true;
+			this->light[index] = *light;
+		}
+		else ASSERT(false);   // FIXME: Support unlimited index
+	}
+
+	void Direct3DStateBlock9::setMaterial(const D3DMATERIAL9 *material)
+	{
+		materialCaptured = true;
+		this->material = *material;
+	}
+
+	void Direct3DStateBlock9::setNPatchMode(float segments)
+	{
+		nPatchModeCaptured = true;
+		nPatchMode = segments;
+	}
+
+	void Direct3DStateBlock9::setPixelShader(Direct3DPixelShader9 *pixelShader)
+	{
+		if(pixelShader) pixelShader->bind();
+		if(this->pixelShader) this->pixelShader->unbind();
+
+		pixelShaderCaptured = true;
+		this->pixelShader = pixelShader;
+	}
+
+	void Direct3DStateBlock9::setPixelShaderConstantB(unsigned int startRegister, const int *constantData, unsigned int count)
+	{
+		memcpy(&pixelShaderConstantB[startRegister], constantData, count * sizeof(int));
+	}
+
+	void Direct3DStateBlock9::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+	{
+		memcpy(pixelShaderConstantF[startRegister], constantData, count * sizeof(float[4]));
+	}
+
+	void Direct3DStateBlock9::setPixelShaderConstantI(unsigned int startRegister, const int *constantData, unsigned int count)
+	{
+		memcpy(pixelShaderConstantI[startRegister], constantData, count * sizeof(int[4]));
+	}
+
+	void Direct3DStateBlock9::setRenderState(D3DRENDERSTATETYPE state, unsigned long value)
+	{
+		renderStateCaptured[state] = true;
+		renderState[state] = value;
+	}
+
+	void Direct3DStateBlock9::setSamplerState(unsigned long index, D3DSAMPLERSTATETYPE state, unsigned long value)
+	{
+		unsigned int sampler = index < 16 ? index : (index - D3DVERTEXTEXTURESAMPLER0) + 16;
+
+		if(sampler >= 16 + 4)
+		{
+			return;
+		}
+
+		samplerStateCaptured[sampler][state] = true;
+		samplerState[sampler][state] = value;
+	}
+
+	void Direct3DStateBlock9::setScissorRect(const RECT *rect)
+	{
+		scissorRectCaptured = true;
+		scissorRect = *rect;
+	}
+
+	void Direct3DStateBlock9::setStreamSource(unsigned int stream, Direct3DVertexBuffer9 *vertexBuffer, unsigned int offset, unsigned int stride)
+	{
+		if(vertexBuffer) vertexBuffer->bind();
+		if(streamSource[stream].vertexBuffer) streamSource[stream].vertexBuffer->unbind();
+
+		streamSourceCaptured[stream] = true;
+		streamSource[stream].vertexBuffer = vertexBuffer;
+		streamSource[stream].offset = offset;
+		streamSource[stream].stride = stride;
+	}
+
+	void Direct3DStateBlock9::setStreamSourceFreq(unsigned int streamNumber, unsigned int divider)
+	{
+		streamSourceFrequencyCaptured[streamNumber] = true;
+		streamSourceFrequency[streamNumber] = divider;
+	}
+
+	void Direct3DStateBlock9::setTexture(unsigned long index, Direct3DBaseTexture9 *texture)
+	{
+		unsigned int sampler = index < 16 ? index : (index - D3DVERTEXTEXTURESAMPLER0) + 16;
+
+		if(sampler >= 16 + 4)
+		{
+			return;
+		}
+
+		if(texture) texture->bind();
+		if(this->texture[sampler]) this->texture[sampler]->unbind();
+
+		textureCaptured[sampler] = true;
+		this->texture[sampler] = texture;
+	}
+
+	void Direct3DStateBlock9::setTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type, unsigned long value)
+	{
+		textureStageStateCaptured[stage][type] = true;
+		textureStageState[stage][type] = value;
+	}
+
+	void Direct3DStateBlock9::setTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
+	{
+		transformCaptured[state] = true;
+		transform[state] = *matrix;
+	}
+
+	void Direct3DStateBlock9::setViewport(const D3DVIEWPORT9 *viewport)
+	{
+		viewportCaptured = true;
+		this->viewport = *viewport;
+	}
+
+	void Direct3DStateBlock9::setVertexDeclaration(Direct3DVertexDeclaration9 *vertexDeclaration)
+	{
+		if(vertexDeclaration) vertexDeclaration->bind();
+		if(this->vertexDeclaration) this->vertexDeclaration->unbind();
+
+		vertexDeclarationCaptured = true;
+		this->vertexDeclaration = vertexDeclaration;
+	}
+
+	void Direct3DStateBlock9::setVertexShader(Direct3DVertexShader9 *vertexShader)
+	{
+		if(vertexShader) vertexShader->bind();
+		if(this->vertexShader) this->vertexShader->unbind();
+
+		vertexShaderCaptured = true;
+		this->vertexShader = vertexShader;
+	}
+
+	void Direct3DStateBlock9::setVertexShaderConstantB(unsigned int startRegister, const int *constantData, unsigned int count)
+	{
+		memcpy(&vertexShaderConstantB[startRegister], constantData, count * sizeof(int));
+	}
+
+	void Direct3DStateBlock9::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
+	{
+		memcpy(vertexShaderConstantF[startRegister], constantData, count * sizeof(float[4]));
+	}
+
+	void Direct3DStateBlock9::setVertexShaderConstantI(unsigned int startRegister, const int *constantData, unsigned int count)
+	{
+		memcpy(vertexShaderConstantI[startRegister], constantData, count * sizeof(int[4]));
+	}
+
+	void Direct3DStateBlock9::clear()
+	{
+		// Erase capture flags
+		fvfCaptured = false;
+		vertexDeclarationCaptured = false;
+
+		indexBufferCaptured = false;
+
+		for(int state = 0; state < D3DRS_BLENDOPALPHA + 1; state++)
+		{
+			renderStateCaptured[state] = false;
+		}
+
+		nPatchModeCaptured = false;
+
+		for(int stage = 0; stage < 8; stage++)
+		{
+			for(int state = 0; state < D3DTSS_CONSTANT + 1; state++)
+			{
+				textureStageStateCaptured[stage][state] = false;
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			for(int state = 0; state < D3DSAMP_DMAPOFFSET + 1; state++)
+			{
+				samplerStateCaptured[sampler][state] = false;
+			}
+		}
+
+		for(int stream = 0; stream < 16; stream++)
+		{
+			streamSourceCaptured[stream] = false;
+			streamSourceFrequencyCaptured[stream] = false;
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			textureCaptured[sampler] = false;
+		}
+
+		for(int state = 0; state < 512; state++)
+		{
+			transformCaptured[state] = false;
+		}
+
+		materialCaptured = false;
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			lightCaptured[index] = false;
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			lightEnableCaptured[index] = false;
+		}
+
+		scissorRectCaptured = false;
+
+		pixelShaderCaptured = false;
+		vertexShaderCaptured = false;
+
+		viewportCaptured = false;
+
+		for(int i = 0; i < 224; i++)
+		{
+			(int&)pixelShaderConstantF[i][0] = 0x80000000;
+			(int&)pixelShaderConstantF[i][1] = 0x80000000;
+			(int&)pixelShaderConstantF[i][2] = 0x80000000;
+			(int&)pixelShaderConstantF[i][3] = 0x80000000;
+		}
+
+		for(int i = 0; i < 256; i++)
+		{
+			(int&)vertexShaderConstantF[i][0] = 0x80000000;
+			(int&)vertexShaderConstantF[i][1] = 0x80000000;
+			(int&)vertexShaderConstantF[i][2] = 0x80000000;
+			(int&)vertexShaderConstantF[i][3] = 0x80000000;
+		}
+
+		for(int i = 0; i < 16; i++)
+		{
+			pixelShaderConstantI[i][0] = 0x80000000;
+			pixelShaderConstantI[i][1] = 0x80000000;
+			pixelShaderConstantI[i][2] = 0x80000000;
+			pixelShaderConstantI[i][3] = 0x80000000;
+
+			pixelShaderConstantB[i] = 0x80000000;
+
+			vertexShaderConstantI[i][0] = 0x80000000;
+			vertexShaderConstantI[i][1] = 0x80000000;
+			vertexShaderConstantI[i][2] = 0x80000000;
+			vertexShaderConstantI[i][3] = 0x80000000;
+
+			vertexShaderConstantB[i] = 0x80000000;
+		}
+
+		for(int index = 0; index < 6; index++)
+		{
+			clipPlaneCaptured[index] = false;
+		}
+
+		paletteNumberCaptured = false;
+
+		// unbind resources
+		if(vertexDeclaration)
+		{
+			vertexDeclaration->unbind();
+			vertexDeclaration = 0;
+		}
+
+		if(indexBuffer)
+		{
+			indexBuffer->unbind();
+			indexBuffer = 0;
+		}
+
+		for(int stream = 0; stream < 16; stream++)
+		{
+			if(streamSource[stream].vertexBuffer)
+			{
+				streamSource[stream].vertexBuffer->unbind();
+				streamSource[stream].vertexBuffer = 0;
+			}
+		}
+
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			if(texture[sampler])
+			{
+				texture[sampler]->unbind();
+				texture[sampler] = 0;
+			}
+		}
+
+		if(pixelShader)
+		{
+			pixelShader->unbind();
+			pixelShader = 0;
+		}
+
+		if(vertexShader)
+		{
+			vertexShader->unbind();
+			vertexShader = 0;
+		}
+	}
+
+	void Direct3DStateBlock9::captureRenderState(D3DRENDERSTATETYPE state)
+	{
+		device->GetRenderState(state, &renderState[state]);
+		renderStateCaptured[state] = true;
+	}
+
+	void Direct3DStateBlock9::captureSamplerState(unsigned long index, D3DSAMPLERSTATETYPE state)
+	{
+		if(index < 16)
+		{
+			device->GetSamplerState(index, state, &samplerState[index][state]);
+			samplerStateCaptured[index][state] = true;
+		}
+		else if(index >= D3DVERTEXTEXTURESAMPLER0)
+		{
+			unsigned int sampler = 16 + (index - D3DVERTEXTEXTURESAMPLER0);
+
+			device->GetSamplerState(index, state, &samplerState[sampler][state]);
+			samplerStateCaptured[sampler][state] = true;
+		}
+	}
+
+	void Direct3DStateBlock9::captureTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type)
+	{
+		device->GetTextureStageState(stage, type, &textureStageState[stage][type]);
+		textureStageStateCaptured[stage][type] = true;
+	}
+
+	void Direct3DStateBlock9::captureTransform(D3DTRANSFORMSTATETYPE state)
+	{
+		device->GetTransform(state, &transform[state]);
+		transformCaptured[state] = true;
+	}
+
+	void Direct3DStateBlock9::capturePixelRenderStates()
+	{
+		captureRenderState(D3DRS_ZENABLE);
+		captureRenderState(D3DRS_FILLMODE);
+		captureRenderState(D3DRS_SHADEMODE);
+		captureRenderState(D3DRS_ZWRITEENABLE);
+		captureRenderState(D3DRS_ALPHATESTENABLE);
+		captureRenderState(D3DRS_LASTPIXEL);
+		captureRenderState(D3DRS_SRCBLEND);
+		captureRenderState(D3DRS_DESTBLEND);
+		captureRenderState(D3DRS_ZFUNC);
+		captureRenderState(D3DRS_ALPHAREF);
+		captureRenderState(D3DRS_ALPHAFUNC);
+		captureRenderState(D3DRS_DITHERENABLE);
+		captureRenderState(D3DRS_FOGSTART);
+		captureRenderState(D3DRS_FOGEND);
+		captureRenderState(D3DRS_FOGDENSITY);
+		captureRenderState(D3DRS_ALPHABLENDENABLE);
+		captureRenderState(D3DRS_DEPTHBIAS);
+		captureRenderState(D3DRS_STENCILENABLE);
+		captureRenderState(D3DRS_STENCILFAIL);
+		captureRenderState(D3DRS_STENCILZFAIL);
+		captureRenderState(D3DRS_STENCILPASS);
+		captureRenderState(D3DRS_STENCILFUNC);
+		captureRenderState(D3DRS_STENCILREF);
+		captureRenderState(D3DRS_STENCILMASK);
+		captureRenderState(D3DRS_STENCILWRITEMASK);
+		captureRenderState(D3DRS_TEXTUREFACTOR);
+		captureRenderState(D3DRS_WRAP0);
+		captureRenderState(D3DRS_WRAP1);
+		captureRenderState(D3DRS_WRAP2);
+		captureRenderState(D3DRS_WRAP3);
+		captureRenderState(D3DRS_WRAP4);
+		captureRenderState(D3DRS_WRAP5);
+		captureRenderState(D3DRS_WRAP6);
+		captureRenderState(D3DRS_WRAP7);
+		captureRenderState(D3DRS_WRAP8);
+		captureRenderState(D3DRS_WRAP9);
+		captureRenderState(D3DRS_WRAP10);
+		captureRenderState(D3DRS_WRAP11);
+		captureRenderState(D3DRS_WRAP12);
+		captureRenderState(D3DRS_WRAP13);
+		captureRenderState(D3DRS_WRAP14);
+		captureRenderState(D3DRS_WRAP15);
+		captureRenderState(D3DRS_COLORWRITEENABLE);
+		captureRenderState(D3DRS_BLENDOP);
+		captureRenderState(D3DRS_SCISSORTESTENABLE);
+		captureRenderState(D3DRS_SLOPESCALEDEPTHBIAS);
+		captureRenderState(D3DRS_ANTIALIASEDLINEENABLE);
+		captureRenderState(D3DRS_TWOSIDEDSTENCILMODE);
+		captureRenderState(D3DRS_CCW_STENCILFAIL);
+		captureRenderState(D3DRS_CCW_STENCILZFAIL);
+		captureRenderState(D3DRS_CCW_STENCILPASS);
+		captureRenderState(D3DRS_CCW_STENCILFUNC);
+		captureRenderState(D3DRS_COLORWRITEENABLE1);
+		captureRenderState(D3DRS_COLORWRITEENABLE2);
+		captureRenderState(D3DRS_COLORWRITEENABLE3);
+		captureRenderState(D3DRS_BLENDFACTOR);
+		captureRenderState(D3DRS_SRGBWRITEENABLE);
+		captureRenderState(D3DRS_SEPARATEALPHABLENDENABLE);
+		captureRenderState(D3DRS_SRCBLENDALPHA);
+		captureRenderState(D3DRS_DESTBLENDALPHA);
+		captureRenderState(D3DRS_BLENDOPALPHA);
+	}
+
+	void Direct3DStateBlock9::capturePixelTextureStates()
+	{
+		for(int stage = 0; stage < 8; stage++)
+		{
+			captureTextureStageState(stage, D3DTSS_COLOROP);
+			captureTextureStageState(stage, D3DTSS_COLORARG1);
+			captureTextureStageState(stage, D3DTSS_COLORARG2);
+			captureTextureStageState(stage, D3DTSS_ALPHAOP);
+			captureTextureStageState(stage, D3DTSS_ALPHAARG1);
+			captureTextureStageState(stage, D3DTSS_ALPHAARG2);
+			captureTextureStageState(stage, D3DTSS_BUMPENVMAT00);
+			captureTextureStageState(stage, D3DTSS_BUMPENVMAT01);
+			captureTextureStageState(stage, D3DTSS_BUMPENVMAT10);
+			captureTextureStageState(stage, D3DTSS_BUMPENVMAT11);
+			captureTextureStageState(stage, D3DTSS_TEXCOORDINDEX);
+			captureTextureStageState(stage, D3DTSS_BUMPENVLSCALE);
+			captureTextureStageState(stage, D3DTSS_BUMPENVLOFFSET);
+			captureTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS);
+			captureTextureStageState(stage, D3DTSS_COLORARG0);
+			captureTextureStageState(stage, D3DTSS_ALPHAARG0);
+			captureTextureStageState(stage, D3DTSS_RESULTARG);
+		}
+	}
+
+	void Direct3DStateBlock9::capturePixelSamplerStates()
+	{
+		for(int sampler = 0; sampler <= D3DVERTEXTEXTURESAMPLER3; sampler++)
+		{
+			captureSamplerState(sampler, D3DSAMP_ADDRESSU);
+			captureSamplerState(sampler, D3DSAMP_ADDRESSV);
+			captureSamplerState(sampler, D3DSAMP_ADDRESSW); 
+			captureSamplerState(sampler, D3DSAMP_BORDERCOLOR);
+			captureSamplerState(sampler, D3DSAMP_MAGFILTER);
+			captureSamplerState(sampler, D3DSAMP_MINFILTER);
+			captureSamplerState(sampler, D3DSAMP_MIPFILTER);
+			captureSamplerState(sampler, D3DSAMP_MIPMAPLODBIAS);
+			captureSamplerState(sampler, D3DSAMP_MAXMIPLEVEL);
+			captureSamplerState(sampler, D3DSAMP_MAXANISOTROPY);
+			captureSamplerState(sampler, D3DSAMP_SRGBTEXTURE);
+			captureSamplerState(sampler, D3DSAMP_ELEMENTINDEX);
+		}
+	}
+
+	void Direct3DStateBlock9::capturePixelShaderStates()
+	{
+		pixelShaderCaptured = true;
+		device->GetPixelShader(reinterpret_cast<IDirect3DPixelShader9**>(&pixelShader));
+		
+		if(pixelShader)
+		{
+			pixelShader->bind();
+			pixelShader->Release();
+		}
+
+		device->GetPixelShaderConstantF(0, pixelShaderConstantF[0], 32);
+		device->GetPixelShaderConstantI(0, pixelShaderConstantI[0], 16);
+		device->GetPixelShaderConstantB(0, pixelShaderConstantB, 16);	
+	}
+
+	void Direct3DStateBlock9::captureVertexRenderStates()
+	{
+		captureRenderState(D3DRS_CULLMODE);
+		captureRenderState(D3DRS_FOGENABLE);
+		captureRenderState(D3DRS_FOGCOLOR);
+		captureRenderState(D3DRS_FOGTABLEMODE);
+		captureRenderState(D3DRS_FOGSTART);
+		captureRenderState(D3DRS_FOGEND);
+		captureRenderState(D3DRS_FOGDENSITY);
+		captureRenderState(D3DRS_RANGEFOGENABLE);
+		captureRenderState(D3DRS_AMBIENT);
+		captureRenderState(D3DRS_COLORVERTEX);
+		captureRenderState(D3DRS_FOGVERTEXMODE);
+		captureRenderState(D3DRS_CLIPPING);
+		captureRenderState(D3DRS_LIGHTING);
+		captureRenderState(D3DRS_LOCALVIEWER);
+		captureRenderState(D3DRS_EMISSIVEMATERIALSOURCE);
+		captureRenderState(D3DRS_AMBIENTMATERIALSOURCE);
+		captureRenderState(D3DRS_DIFFUSEMATERIALSOURCE);
+		captureRenderState(D3DRS_SPECULARMATERIALSOURCE);
+		captureRenderState(D3DRS_VERTEXBLEND);
+		captureRenderState(D3DRS_CLIPPLANEENABLE);
+		captureRenderState(D3DRS_POINTSIZE);
+		captureRenderState(D3DRS_POINTSIZE_MIN);
+		captureRenderState(D3DRS_POINTSPRITEENABLE);
+		captureRenderState(D3DRS_POINTSCALEENABLE);
+		captureRenderState(D3DRS_POINTSCALE_A);
+		captureRenderState(D3DRS_POINTSCALE_B);
+		captureRenderState(D3DRS_POINTSCALE_C);
+		captureRenderState(D3DRS_MULTISAMPLEANTIALIAS);
+		captureRenderState(D3DRS_MULTISAMPLEMASK);
+		captureRenderState(D3DRS_PATCHEDGESTYLE);
+		captureRenderState(D3DRS_POINTSIZE_MAX);
+		captureRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE);
+		captureRenderState(D3DRS_TWEENFACTOR);
+		captureRenderState(D3DRS_POSITIONDEGREE);
+		captureRenderState(D3DRS_NORMALDEGREE);
+		captureRenderState(D3DRS_MINTESSELLATIONLEVEL);
+		captureRenderState(D3DRS_MAXTESSELLATIONLEVEL);
+		captureRenderState(D3DRS_ADAPTIVETESS_X);
+		captureRenderState(D3DRS_ADAPTIVETESS_Y);
+		captureRenderState(D3DRS_ADAPTIVETESS_Z);
+		captureRenderState(D3DRS_ADAPTIVETESS_W);
+		captureRenderState(D3DRS_ENABLEADAPTIVETESSELLATION);
+		captureRenderState(D3DRS_NORMALIZENORMALS);
+		captureRenderState(D3DRS_SPECULARENABLE);
+		captureRenderState(D3DRS_SHADEMODE);
+	}
+
+	void Direct3DStateBlock9::captureVertexSamplerStates()
+	{
+		for(int sampler = 0; sampler <= D3DVERTEXTEXTURESAMPLER3; sampler++)
+		{
+			captureSamplerState(sampler, D3DSAMP_DMAPOFFSET);
+		}
+	}
+
+	void Direct3DStateBlock9::captureVertexTextureStates()
+	{
+		for(int stage = 0; stage < 8; stage++)
+		{
+			captureTextureStageState(stage, D3DTSS_TEXCOORDINDEX);
+			captureTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS);
+		}
+	}
+
+	void Direct3DStateBlock9::captureNPatchMode()
+	{
+		nPatchMode = device->GetNPatchMode();
+		nPatchModeCaptured = true;
+	}
+
+	void Direct3DStateBlock9::captureLightStates()
+	{
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			long result = device->GetLight(index, &light[index]);
+			lightCaptured[index] = SUCCEEDED(result);
+		}
+
+		for(int index = 0; index < 8; index++)   // FIXME: Support unlimited index
+		{
+			lightEnableState[index] = false;
+			long result = device->GetLightEnable(index, &lightEnableState[index]);
+			lightEnableCaptured[index] = SUCCEEDED(result);
+		}
+	}
+
+	void Direct3DStateBlock9::captureVertexShaderStates()
+	{
+		vertexShaderCaptured = true;
+		device->GetVertexShader(reinterpret_cast<IDirect3DVertexShader9**>(&vertexShader));
+		
+		if(vertexShader)
+		{
+			vertexShader->bind();
+			vertexShader->Release();
+		}
+
+		device->GetVertexShaderConstantF(0, vertexShaderConstantF[0], 256);
+		device->GetVertexShaderConstantI(0, vertexShaderConstantI[0], 16);
+		device->GetVertexShaderConstantB(0, vertexShaderConstantB, 16);		
+	}
+
+	void Direct3DStateBlock9::captureStreamSourceFrequencies()
+	{
+		for(int stream = 0; stream < 16; stream++)
+		{
+			streamSourceFrequencyCaptured[stream] = true;
+			device->GetStreamSourceFreq(stream, &streamSourceFrequency[stream]);
+		}
+	}
+
+	void Direct3DStateBlock9::captureFVF()
+	{
+		device->GetFVF(&FVF);
+		fvfCaptured = true;
+	}
+	
+	void Direct3DStateBlock9::captureVertexDeclaration()
+	{
+		vertexDeclarationCaptured = true;
+		device->GetVertexDeclaration(reinterpret_cast<IDirect3DVertexDeclaration9**>(&vertexDeclaration));
+
+		if(vertexDeclaration)
+		{
+			vertexDeclaration->bind();
+			vertexDeclaration->Release();
+		}
+	}
+
+	void Direct3DStateBlock9::captureTextures()
+	{
+		for(int sampler = 0; sampler < 16 + 4; sampler++)
+		{
+			textureCaptured[sampler] = true;
+			int index = sampler < 16 ? sampler : D3DVERTEXTEXTURESAMPLER0 + (sampler - 16);
+			device->GetTexture(index, reinterpret_cast<IDirect3DBaseTexture9**>(&texture[sampler]));
+
+			if(texture[sampler])
+			{
+				texture[sampler]->bind();
+				texture[sampler]->Release();
+			}
+		}
+	}
+
+	void Direct3DStateBlock9::captureTexturePalette()
+	{
+		paletteNumberCaptured = true;
+		device->GetCurrentTexturePalette(&paletteNumber);
+	}
+
+	void Direct3DStateBlock9::captureVertexStreams()
+	{
+		for(int stream = 0; stream < 16; stream++)
+		{
+			streamSourceCaptured[stream] = true;
+			device->GetStreamSource(stream, reinterpret_cast<IDirect3DVertexBuffer9**>(&streamSource[stream].vertexBuffer), &streamSource[stream].offset, &streamSource[stream].stride);
+			
+			if(streamSource[stream].vertexBuffer)
+			{
+				streamSource[stream].vertexBuffer->bind();
+				streamSource[stream].vertexBuffer->Release();
+			}
+		}
+	}
+
+	void Direct3DStateBlock9::captureIndexBuffer()
+	{
+		indexBufferCaptured = true;
+		device->GetIndices(reinterpret_cast<IDirect3DIndexBuffer9**>(&indexBuffer));
+
+		if(indexBuffer)
+		{
+			indexBuffer->bind();
+			indexBuffer->Release();
+		}
+	}
+
+	void Direct3DStateBlock9::captureViewport()
+	{
+		device->GetViewport(&viewport);
+		viewportCaptured = true;
+	}
+
+	void Direct3DStateBlock9::captureScissorRectangle()
+	{
+		device->GetScissorRect(&scissorRect);
+		scissorRectCaptured = true;
+	}
+
+	void Direct3DStateBlock9::captureTransforms()
+	{
+		captureTransform(D3DTS_VIEW);
+		captureTransform(D3DTS_PROJECTION);
+		captureTransform(D3DTS_WORLD);
+	}
+
+	void Direct3DStateBlock9::captureTextureTransforms()
+	{
+		captureTransform(D3DTS_TEXTURE0);
+		captureTransform(D3DTS_TEXTURE1);
+		captureTransform(D3DTS_TEXTURE2);
+		captureTransform(D3DTS_TEXTURE3);
+		captureTransform(D3DTS_TEXTURE4);
+		captureTransform(D3DTS_TEXTURE5);
+		captureTransform(D3DTS_TEXTURE6);
+		captureTransform(D3DTS_TEXTURE7);
+	}
+
+	void Direct3DStateBlock9::captureClippingPlanes()
+	{
+		for(int index = 0; index < 6; index++)
+		{
+			device->GetClipPlane(index, (float*)&clipPlane[index]);
+			clipPlaneCaptured[index] = true;
+		}
+	}
+
+	void Direct3DStateBlock9::captureMaterial()
+	{
+		device->GetMaterial(&material);
+		materialCaptured = true;
+	}
+}