//[-------------------------------------------------------]
//[ Private virtual SPMultiView functions                 ]
//[-------------------------------------------------------]
void SPMultiViewFixedFunctions::DrawScene(uint32 nScene)
{
	// Get the used renderer
	Renderer &cRenderer = GetRenderer();

	// Fixed functions support required
	FixedFunctions *pFixedFunctions = cRenderer.GetFixedFunctions();
	if (pFixedFunctions) {
		{ // Setup light
			FixedFunctions::Light sLight;
			pFixedFunctions->GetDefaultLightSettings(sLight);
			sLight.cAmbient.SetRGBA(0.1f, 0.1f, 0.1f, 1.0f);
			sLight.cDiffuse.SetRGBA(1.0f, 1.0f, 1.0f, 1.0f);
			sLight.nType = FixedFunctions::LightType::Point;
			sLight.vPosition.SetXYZ(0.0f, 0.0f, 1.5f);
			sLight.fLinearAttenuation = 0.3f;
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::World, Matrix4x4::Identity);
			pFixedFunctions->SetLightEnabled(0, false);
			pFixedFunctions->SetLight		(0, sLight);
			pFixedFunctions->SetLightEnabled(0, true);
		}

		{ // Set the world matrix
			// Build a rotation matrix by using a given Euler angle around the y-axis
			Matrix4x4 mWorld;
			mWorld.FromEulerAngleY(static_cast<float>(m_fRotation*Math::DegToRad));
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::World, mWorld);
		}

		{ // Set the view matrix
			Matrix4x4 mView;
			mView.SetTranslation(0.0f, 0.0f, -10.0f);
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::View, mView);
		}

		{ // Set the projection matrix
			Matrix4x4 mProj;
			const float fAspect      = 1.0f;
			const float fAspectRadio = cRenderer.GetViewport().GetWidth()/(cRenderer.GetViewport().GetHeight()*fAspect);
			mProj.PerspectiveFov(static_cast<float>(45.0f*Math::DegToRad), fAspectRadio, 0.001f, 1000.0f);
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::Projection, mProj);
		}

		// Draw the mesh handler representing the scene to draw
		switch (nScene) {
			case 0:
				m_pMeshHandlerSphere->Draw();
				break;

			case 1:
				m_pMeshHandlerTorus->Draw();
				break;

			case 2:
				m_pMeshHandlerCube->Draw();
				break;
		}
	}
}
//[-------------------------------------------------------]
//[ Private virtual PLRenderer::SurfacePainter functions  ]
//[-------------------------------------------------------]
void SPTriangleFixedFunctions::OnPaint(Surface &cSurface)
{
	// Get the used renderer
	Renderer &cRenderer = GetRenderer();

	// Clear the content of the current used render target by using gray (this way, in case on an graphics error we might still see at least something)
	cRenderer.Clear(Clear::Color | Clear::ZBuffer, Color4::Gray);

	// Fixed functions support required
	FixedFunctions *pFixedFunctions = cRenderer.GetFixedFunctions();
	if (pFixedFunctions) {
		{ // Set the world matrix
			// Build a rotation matrix by using a given Euler angle around the y-axis
			Matrix4x4 mWorld;
			mWorld.FromEulerAngleY(static_cast<float>(m_fRotation*Math::DegToRad));
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::World, mWorld);

			// Increase the rotation by the current time difference (time past since the last frame)
			// -> Normally, such work should NOT be performed within the rendering step, but we want
			//    to keep the implementation simple in here...
			m_fRotation += Timing::GetInstance()->GetTimeDifference()*50;
		}

		{ // Set the view matrix
			Matrix4x4 mView;
			mView.SetTranslation(0.0f, 0.0f, -5.0f);
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::View, mView);
		}

		{ // Set the projection matrix
			const float fAspect      = 1.0f;
			const float fAspectRadio = cRenderer.GetViewport().GetWidth()/(cRenderer.GetViewport().GetHeight()*fAspect);
			Matrix4x4 mProj;
			mProj.PerspectiveFov(static_cast<float>(45.0f*Math::DegToRad), fAspectRadio, 0.001f, 1000.0f);
			pFixedFunctions->SetTransformState(FixedFunctions::Transform::Projection, mProj);
		}

		// Normally this vertex buffer we created is NEVER a null pointer, but in this sample
		// we want to go for sure
		if (m_pVertexBuffer) {
			// Bind our vertex buffer
			pFixedFunctions->SetVertexBuffer(m_pVertexBuffer);

			// No back face culling, please. Else we can only see one 'side' of the triangle
			cRenderer.SetRenderState(RenderState::CullMode, Cull::None);

			// Now draw the primitives of our cool triangle.
			// The primitive type is 'triangles', we start at vertex 0 and draw '3' vertices.
			cRenderer.DrawPrimitives(Primitive::TriangleList, 0, 3);
		}
	}
}
//[-------------------------------------------------------]
//[ Private virtual PLRenderer::SurfacePainter functions  ]
//[-------------------------------------------------------]
void SPRTTShaders::OnPaint(Surface &cSurface)
{
	// Get the used renderer
	Renderer &cRenderer = GetRenderer();

	// Clear the content of the current used render target by using gray (this way, in case on an graphics error we might still see at least something)
	cRenderer.Clear(Clear::Color | Clear::ZBuffer, Color4::Gray);

	// Backup current render target and set the new one to render in our texture buffer
	Surface *pRenderSurfaceBackup = cRenderer.GetRenderTarget();
	if (cRenderer.SetRenderTarget(m_pRenderTarget)) {
		if (m_pColorTarget1)
			cRenderer.SetColorRenderTarget(static_cast<TextureBuffer*>(m_pColorTarget1), 1);
		if (m_pColorTarget2)
			cRenderer.SetColorRenderTarget(static_cast<TextureBuffer*>(m_pColorTarget2), 2);
		if (m_pColorTarget3)
			cRenderer.SetColorRenderTarget(static_cast<TextureBuffer*>(m_pColorTarget3), 3);

		// Draw the scene
		DrawScene(cRenderer);

		// Reset render target
		cRenderer.SetRenderTarget(pRenderSurfaceBackup);
	}

	// This code is similar to the code of the triangle sample. But instead of a
	// triangle we will draw three rotating quadrangles. Further the used vertex
	// buffer has texture coordinates and we apply the 'teapot' texture buffer on the primitives.
	// Clear the content of the current used render target

	// Make our program to the current one
	if (cRenderer.SetProgram(m_pProgram)) {
		// Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute"
		m_pProgram->Set("VertexPosition",		   m_pPositionVertexBuffer, VertexBuffer::Position);
		m_pProgram->Set("VertexTextureCoordinate", m_pPositionVertexBuffer, VertexBuffer::TexCoord);
		m_pProgram->Set("VertexColor",			   m_pColorVertexBuffer,    VertexBuffer::Color);

		// Set color factor
		m_pProgram->Set("ColorFactor", 0.0f);

		// Calculate the composed view projection matrix - we need it multiple times
		Matrix4x4 mViewProjection;
		{
			// Calculate the view matrix
			Matrix4x4 mView;
			{
				mView.SetTranslation(0.0f, 0.0f, -5.0f);
			}

			// Calculate the projection matrix
			Matrix4x4 mProjection;
			{
				const float fAspect      = 1.0f;
				const float fAspectRadio = cRenderer.GetViewport().GetWidth()/(cRenderer.GetViewport().GetHeight()*fAspect);
				mProjection.PerspectiveFov(static_cast<float>(45.0f*Math::DegToRad), fAspectRadio, 0.001f, 1000.0f);
			}

			// Calculate the composed view projection matrix
			mViewProjection = mProjection*mView;
		}

		// No back face culling, please. Else we can only see one 'side' of the quadrangle
		cRenderer.SetRenderState(RenderState::CullMode, Cull::None);

		Matrix4x4 mWorld;
		{ // Draw quadrangle 1: Primary render target
			// Set object space to clip space matrix uniform
			ProgramUniform *pProgramUniform = m_pProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
			if (pProgramUniform) {
				mWorld.SetTranslationMatrix(2.0f, 1.0f, 0.0f);
				pProgramUniform->Set(mViewProjection*mWorld);
			}

			{ // Set the texture buffer we rendered our teapot in as the current texture buffer
				const int nTextureUnit = m_pProgram->Set("DiffuseMap", m_pRenderTarget->GetTextureBuffer());
				if (nTextureUnit >= 0) {
					// Disable mip mapping - this is required because we created/filled no mipmaps for your texture buffer
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None);
				}
			}

			// Draw
			cRenderer.DrawPrimitives(Primitive::TriangleStrip, 0, 4);
		}

		{ // Draw quadrangle 2: Color render target 1
			// Set object space to clip space matrix uniform
			ProgramUniform *pProgramUniform = m_pProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
			if (pProgramUniform) {
				mWorld.FromEulerAngleY(static_cast<float>(m_fRotation*Math::DegToRad));
				mWorld.SetTranslation(-2.0f, 1.0f, 0.0f);
				pProgramUniform->Set(mViewProjection*mWorld);
			}

			{ // Set the texture buffer we rendered our teapot in as the current texture buffer
				const int nTextureUnit = m_pProgram->Set("DiffuseMap", m_pColorTarget1 ? static_cast<TextureBuffer*>(m_pColorTarget1) : m_pRenderTarget->GetTextureBuffer());
				if (nTextureUnit >= 0) {
					// Disable mip mapping - this is required because we created/filled no mipmaps for your texture buffer
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None);
				}
			}

			// Draw
			cRenderer.DrawPrimitives(Primitive::TriangleStrip, 0, 4);
		}

		{ // Draw quadrangle 3: Color render target 2
			// Set object space to clip space matrix uniform
			ProgramUniform *pProgramUniform = m_pProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
			if (pProgramUniform) {
				mWorld.FromEulerAngleZ(static_cast<float>(m_fRotation*Math::DegToRad));
				mWorld.SetTranslation(0.0f, 1.0f, 0.0f);
				pProgramUniform->Set(mViewProjection*mWorld);
			}

			{ // Set the texture buffer we rendered our teapot in as the current texture buffer
				const int nTextureUnit = m_pProgram->Set("DiffuseMap", m_pColorTarget2 ? static_cast<TextureBuffer*>(m_pColorTarget2) : m_pRenderTarget->GetTextureBuffer());
				if (nTextureUnit >= 0) {
					// Disable mip mapping - this is required because we created/filled no mipmaps for your texture buffer
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None);
				}
			}

			// Draw
			cRenderer.DrawPrimitives(Primitive::TriangleStrip, 0, 4);
		}

		{ // Draw quadrangle 4: Color render target 3
			// Set object space to clip space matrix uniform
			ProgramUniform *pProgramUniform = m_pProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
			if (pProgramUniform) {
				mWorld.FromEulerAngleZ(static_cast<float>(-m_fRotation*Math::DegToRad));
				mWorld.SetTranslation(-2.0f, -1.0f, 0.0f);
				pProgramUniform->Set(mViewProjection*mWorld);
			}

			{ // Set the texture buffer we rendered our teapot in as the current texture buffer
				const int nTextureUnit = m_pProgram->Set("DiffuseMap", m_pColorTarget3 ? static_cast<TextureBuffer*>(m_pColorTarget3) : m_pRenderTarget->GetTextureBuffer());
				if (nTextureUnit >= 0) {
					// Disable mip mapping - this is required because we created/filled no mipmaps for your texture buffer
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None);
				}
			}

			// Draw
			cRenderer.DrawPrimitives(Primitive::TriangleStrip, 0, 4);
		}

		{ // Draw quadrangle 4: Primary render target, but with per vertex color - the primitive will be quite colorful :)
			// Set object space to clip space matrix uniform
			ProgramUniform *pProgramUniform = m_pProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
			if (pProgramUniform) {
				mWorld.FromEulerAngleZ(static_cast<float>(-m_fRotation*Math::DegToRad));
				mWorld.SetTranslation(2.0f, -1.0f, 0.0f);
				pProgramUniform->Set(mViewProjection*mWorld);
			}

			// Set color factor
			m_pProgram->Set("ColorFactor", 1.0f);

			{ // Set the texture buffer we rendered our teapot in as the current texture buffer
				const int nTextureUnit = m_pProgram->Set("DiffuseMap", m_pRenderTarget->GetTextureBuffer());
				if (nTextureUnit >= 0) {
					// Disable mip mapping - this is required because we created/filled no mipmaps for your texture buffer
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::Linear);
					cRenderer.SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None);
				}
			}

			// Draw
			cRenderer.DrawPrimitives(Primitive::TriangleStrip, 0, 4);
		}

		// Change the backface culling back to the default setting
		cRenderer.SetRenderState(RenderState::CullMode, Cull::CCW);
	}

	// Increase the rotation by the current time difference (time past since the last frame)
	// -> Normally, such work should NOT be performed within the rendering step, but we want
	//    to keep the implementation simple in here...
	m_fRotation += Timing::GetInstance()->GetTimeDifference()*50;
}
/**
*  @brief
*    Draws the scene
*/
void SPRTTShaders::DrawScene(Renderer &cRenderer)
{
	// Clear the content of the current used render target by using gray (this way, in case on an graphics error we might still see at least something)
	cRenderer.Clear(Clear::Color | Clear::ZBuffer, Color4::Gray);

	// Make our program to the current one
	if (cRenderer.SetProgram(m_pSceneProgram)) {
		// Calculate the world matrix
		Matrix4x4 mWorld;
		{
			// Build a rotation matrix by using a given Euler angle around the y-axis
			mWorld.FromEulerAngleY(static_cast<float>(m_fRotation*Math::DegToRad));
		}

		// Set program uniforms
		ProgramUniform *pProgramUniform = m_pSceneProgram->GetUniform("ObjectSpaceToClipSpaceMatrix");
		if (pProgramUniform) {
			// Calculate the view matrix
			Matrix4x4 mView;
			{
				mView.SetTranslation(0.0f, -0.1f, -0.5f);
			}

			// Calculate the projection matrix
			Matrix4x4 mProjection;
			{
				const float fAspect      = 1.0f;
				const float fAspectRadio = cRenderer.GetViewport().GetWidth()/(cRenderer.GetViewport().GetHeight()*fAspect);
				mProjection.PerspectiveFov(static_cast<float>(45.0f*Math::DegToRad), fAspectRadio, 0.001f, 1000.0f);
			}

			// Calculate the final composed world view projection matrix
			const Matrix4x4 mWorldViewProjection = mProjection*mView*mWorld;

			// Set object space to clip space matrix uniform
			pProgramUniform->Set(mWorldViewProjection);
		}

		// Set object space to world space matrix uniform
		pProgramUniform = m_pSceneProgram->GetUniform("ObjectSpaceToWorldSpaceMatrix");
		if (pProgramUniform)
			pProgramUniform->Set(mWorld);

		// Set world space light direction
		pProgramUniform = m_pSceneProgram->GetUniform("LightDirection");
		if (pProgramUniform)
			pProgramUniform->Set(Vector3::UnitZ);

		// Get the used mesh
		const Mesh *pMesh = m_pMeshHandler->GetMesh();
		if (pMesh) {
			// Get the mesh LOD level to use
			const MeshLODLevel *pLODLevel = pMesh->GetLODLevel(0);
			if (pLODLevel && pLODLevel->GetIndexBuffer()) {
				// Get and use the index buffer of the mesh LOD level
				cRenderer.SetIndexBuffer(pLODLevel->GetIndexBuffer());

				// Get the vertex buffer of the mesh handler
				VertexBuffer *pVertexBuffer = m_pMeshHandler->GetVertexBuffer();
				if (pVertexBuffer) {
					// Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute"
					ProgramAttribute *pProgramAttribute = m_pSceneProgram->GetAttribute("VertexPosition");
					if (pProgramAttribute)
						pProgramAttribute->Set(pVertexBuffer, VertexBuffer::Position);
					pProgramAttribute = m_pSceneProgram->GetAttribute("VertexNormal");
					if (pProgramAttribute)
						pProgramAttribute->Set(pVertexBuffer, VertexBuffer::Normal);

					// Loop through all geometries of the mesh
					const Array<Geometry> &lstGeometries = *pLODLevel->GetGeometries();
					for (uint32 nGeo=0; nGeo<lstGeometries.GetNumOfElements(); nGeo++) {
						// Is this geometry active?
						const Geometry &cGeometry = lstGeometries[nGeo];
						if (cGeometry.IsActive()) {
							// Draw the geometry
							cRenderer.DrawIndexedPrimitives(
								cGeometry.GetPrimitiveType(),
								0,
								pVertexBuffer->GetNumOfElements()-1,
								cGeometry.GetStartIndex(),
								cGeometry.GetIndexSize()
							);
						}
					}
				}
			}
		}
	}
}