void ParticleManager::UpdateParticles(float dt, DxGraphics* pDxGraphics, Camera& cam)
{
	// Update the world mat
	XMMATRIX transMat = XMMatrixTranslation(0.0f, 0.0f, 0.0f);
	XMMATRIX rotMat = XMMatrixRotationRollPitchYaw(0.0f, 0.0f, 0.0f);
	XMMATRIX scaleMat = XMMatrixScaling(1.0f, 1.0f, 1.0f);

	m_worldMat = rotMat * scaleMat * transMat;

	cam.CalculateViewMatrix();

	// stream out the particles which runs through the physics
	XMMATRIX tWorld = XMMatrixTranspose(m_worldMat);
	XMMATRIX tView = XMMatrixTranspose(cam.GetViewMatrix());
	XMMATRIX tProj = XMMatrixTranspose(cam.GetProjMatrix());

	m_massPoint.dt = dt;

	ID3D11DeviceContext* pCon = pDxGraphics->GetImmediateContext();

	// Set the stream out buffer
	UINT offsetSO[1] = { 0 };
	pCon->SOSetTargets(1, &m_vStream, offsetSO);

	UINT stride = sizeof(Particle);
	UINT offset = 0;

	pCon->IASetVertexBuffers(0, 1, &m_vBuffer, &stride, &offset);
	pCon->IASetInputLayout(m_inputLayout);
	pCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);

	pCon->VSSetShader(m_vUpdate, 0, 0);
	pCon->GSSetShader(m_gUpdate, 0, 0);
	pCon->PSSetShader(NULL, 0, 0);

	//// Update the cBuffer
	pCon->UpdateSubresource(m_pointBuffer, 0, NULL, &m_massPoint, 0, 0);

	pCon->VSSetConstantBuffers(3, 1, &m_pointBuffer);

	pCon->Draw(m_particleList.size(), 0);

	pCon->VSSetShader(NULL, 0, 0);
	pCon->GSSetShader(NULL, 0, 0);
	pCon->PSSetShader(NULL, 0, 0);

	// Unbind the SO
	ID3D11Buffer* bufferArray[1] = { 0 };
	pCon->SOSetTargets(1, bufferArray, offsetSO);
	
	std::swap(m_vStream, m_vBuffer);
}
void ParticleGenerator::Update(Transform eTransform, float dt, float tt) {
	ResourceManager* rManager = ResourceManager::Instance();
	ID3D11DeviceContext* deviceContext = rManager->GetDeviceContext();
	UINT stride = sizeof(Particle);
	UINT offset = 0;
	generatorVS = dynamic_cast<SimpleVertexShader*>(rManager->GetShader("ParticleGeneratorVS"));
	generatorGS = dynamic_cast<SimpleGeometryShader*>(rManager->GetShader("ParticleGeneratorGS"));

	DirectX::XMMATRIX translationMat = DirectX::XMMatrixTranslation(position.x, position.y, position.z);
	DirectX::XMMATRIX rotationMat = DirectX::XMMatrixRotationRollPitchYaw(eTransform.GetRotation().x * 2, eTransform.GetRotation().y * 2, eTransform.GetRotation().z * 2);
	DirectX::XMFLOAT4X4 transformMat;
	DirectX::XMStoreFloat4x4(&transformMat, DirectX::XMMatrixTranspose(translationMat * rotationMat));
	DirectX::XMFLOAT3 finalPos = DirectX::XMFLOAT3(eTransform.GetTranslation().x + transformMat._14, eTransform.GetTranslation().y + transformMat._24, eTransform.GetTranslation().z + transformMat._34);

	// Set constant variables
	generatorGS->SetFloat("dt", dt);
	generatorGS->SetFloat("tt", tt);
	generatorGS->SetFloat3("generatorPos", finalPos);
	generatorGS->SetFloat("spawnRate", spawnRate);
	generatorGS->SetFloat("lifeTime", lifeTime);
	generatorGS->SetSamplerState("randomSampler", rManager->GetSamplerState("trilinear"));
	generatorGS->SetShaderResourceView("randomTexture", rManager->GetTexture("randomTexture"));

	// Activate shaders
	generatorVS->SetShader(true);
	generatorGS->SetShader(true);
	deviceContext->PSSetShader(0, 0, 0);

	// Unbind vertex buffers (incase)
	ID3D11Buffer* unset = 0;
	UINT unsetStride = 0;
	deviceContext->IASetVertexBuffers(0, 1, &unset, &stride, &offset);
	deviceContext->IASetVertexBuffers(0, 1, &readBuff, &stride, &offset);
	deviceContext->SOSetTargets(1, &writeBuff, &offset);
	deviceContext->DrawAuto();

	// Kill everything
	SimpleGeometryShader::UnbindStreamOutStage(deviceContext);
	deviceContext->GSSetShader(0, 0, 0);
	SwapBuffers();
}
ParticleGenerator::ParticleGenerator(Particle p, DirectX::XMFLOAT3 pos, float lt, float sr, float numRoots)
{
	init = false;
	lifeTime = lt;
	spawnRate = sr;
	position = pos;

	// Get necessary resources
	ResourceManager* rManager = ResourceManager::Instance();
	ID3D11Device* device = rManager->GetDevice();
	ID3D11DeviceContext* deviceContext = rManager->GetDeviceContext();

	generatorVS = dynamic_cast<SimpleVertexShader*>(rManager->GetShader("ParticleGeneratorVS"));
	generatorGS = dynamic_cast<SimpleGeometryShader*>(rManager->GetShader("ParticleGeneratorGS"));

	// Create Stream Output variables
	generatorGS->CreateCompatibleStreamOutBuffer(&readBuff, 1000000);
	generatorGS->CreateCompatibleStreamOutBuffer(&writeBuff, 1000000);

	// Create initial ROOT vertex buffer
	UINT stride = sizeof(Particle);
	UINT offset = 0;
	Particle vertices[] = { p };

	D3D11_BUFFER_DESC vbd;
	vbd.Usage = D3D11_USAGE_IMMUTABLE;
	vbd.ByteWidth = sizeof(Particle);
	vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vbd.CPUAccessFlags = 0;
	vbd.MiscFlags = 0;
	vbd.StructureByteStride = 0;
	D3D11_SUBRESOURCE_DATA initialVertexData;
	initialVertexData.pSysMem = vertices;
	device->CreateBuffer(&vbd, &initialVertexData, &particleBuff);

	// Set constant variables
	generatorGS->SetFloat("dt", 0.0f);
	generatorGS->SetFloat("tt", 0.0f);
	generatorGS->SetFloat("lifeTime", lifeTime);
	generatorGS->SetFloat("spawnRate", spawnRate);
	generatorGS->SetFloat3("generatorPos", position);
	generatorGS->SetSamplerState("randomSampler", rManager->GetSamplerState("trilinear"));
	generatorGS->SetShaderResourceView("randomTexture", rManager->GetTexture("randomTexture"));

	// Activate shaders
	generatorVS->SetShader(true);
	generatorGS->SetShader(true);
	deviceContext->PSSetShader(0, 0, 0);
	deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);

	// Unbind vertex buffers (incase)
	ID3D11Buffer* unset = 0;
	deviceContext->IASetVertexBuffers(0, 1, &unset, &stride, &offset);

	deviceContext->IASetVertexBuffers(0, 1, &particleBuff, &stride, &offset);
	deviceContext->SOSetTargets(1, &writeBuff, &offset);
	deviceContext->Draw(1, 0);

	SimpleGeometryShader::UnbindStreamOutStage(deviceContext);
	deviceContext->GSSetShader(0, 0, 0);
	SwapBuffers();
}
void ParticleSystem::Draw(const Camera& cam)
{
	Matrix44f VP = cam.getProjectionMatrix() * cam.getModelViewMatrix();

	ID3D11DeviceContext* dc = getImmediateContext();

	//
	// Set constants.
	//
	mFX.uniform("gViewProj", VP);
	mFX.uniform("gGameTime", mGameTime);
	mFX.uniform("gTimeStep", mTimeStep);
	mFX.uniform("gEyePosW", mEyePosW);
	mFX.uniform("gEmitPosW", mEmitPosW);
	mFX.uniform("gEmitDirW", mEmitDirW);
	mFX.uniform("gTexture", mTexure);
	mFX.uniform("gRandomTex", mRandomTex);

	//
	// Set IA stage.
	//
	dc->IASetInputLayout(mInputLayout);
	dc->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);

	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	// On the first pass, use the initialization VB.  Otherwise, use
	// the VB that contains the current particle list.
	if( mFirstRun )
		dc->IASetVertexBuffers(0, 1, &mInitVB, &stride, &offset);
	else
		dc->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);

	//
	// Draw the current particle list using stream-out only to update them.  
	// The updated vertices are streamed-out to the target VB. 
	//
	dc->SOSetTargets(1, &mStreamOutVB, &offset);
	mFX.useTechnique("StreamOutTech");
	if (mFirstRun)
	{
		mFX.draw(1);
		mFirstRun = false;
	}
	else
		mFX.drawAuto();

	// done streaming-out--unbind the vertex buffer
	ID3D11Buffer* bufferArray[1] = {0};
	dc->SOSetTargets(1, bufferArray, &offset);

	// ping-pong the vertex buffers
	std::swap(mDrawVB, mStreamOutVB);

	//
	// Draw the updated particle system we just streamed-out. 
	//
	dc->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);

	mFX.useTechnique("DrawTech");
	mFX.drawAuto();
}