//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "Geometry.h"
#include "Permutations.h"
#include "ImageManagement.h"
#include "qamath.h"
#include "Transforms.h"
#include "TransformWrapper.h"
#include "TranslateTest.h"
#include <d3dm.h>
#include <tux.h>
#include "DebugOutput.h"

TESTPROCAPI TranslateTest(LPDIRECT3DMOBILEDEVICE pDevice,
                          D3DMTRANSFORMSTATETYPE TransMatrix,
                          D3DQA_TRANSLATETYPE TranslateType,
                          UINT uiFrameNumber,
						  D3DMFORMAT Format,
                          UINT uiTestID, 
                          WCHAR *wszImageDir,
                          UINT uiInstanceHandle,
                          HWND hWnd,
                          LPTESTCASEARGS pTestCaseArgs)
{
    HRESULT hr;
    
	//
	// Level of detail in sphere model
	//
	CONST UINT uiNumDivisions = 12;

	//
	// Translate factors, per axis
	//
	float fX, fY, fZ;

	//
	// Temporary values used while computing per-axis translation factors
	//
	float fAxis1, fAxis2;

	//
	// Number of axis used for a particular translation
	//
	UINT uiNumAxis;

	//
	// Each test case consists of multiple rendered frames
	//
	UINT uiFrame;

	//
	// Translate matrix to be applied to Direct3D TnL
	//
	D3DMMATRIX TranslateMatrix;

	//
	// Interfaces for scene data
	//
	LPDIRECT3DMOBILEVERTEXBUFFER pVBSphere = NULL;
	LPDIRECT3DMOBILEINDEXBUFFER pIBSphere = NULL;

	//
	// All failure conditions set this to an error
	//
	INT iTestResult = TPR_PASS;

	//
	// Number of frames expected to be generated by this test case
	//
	UINT uiNumDesiredFrames;

	//
	// The geometry-generating algorithm reports it's "specs"; useful at
	// DrawPrimitive-time
	//
	D3DMPRIMITIVETYPE PrimType;
	UINT uiPrimCount;
	UINT uiNumVertices;

	UINT uiTotalFrames;

	//
	// Flat shading is in base profile
	//
	pDevice->SetRenderState( D3DMRS_SHADEMODE, D3DMSHADE_FLAT );

	//
	// Lighting is "baked" in verts
	//
	pDevice->SetRenderState( D3DMRS_LIGHTING, 0 );

	pDevice->SetRenderState(D3DMRS_CULLMODE, D3DMCULL_CW);


	//
	// Enable clipping
	//
	if( FAILED( hr = pDevice->SetRenderState(D3DMRS_CLIPPING, TRUE)))
	{
		DebugOut(L"SetRenderState(D3DMRS_CLIPPING,TRUE) failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = GetAxisCount(&uiNumAxis, TranslateType)))
	{
		DebugOut(L"GetNumberofAxis failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	//
	// Valid range is [1,3]
	//
	if (!((1 <= uiNumAxis) &&
	      (3 >= uiNumAxis)))
	{
		DebugOut(
		    L"GetAxisCount resulted in invalid number of axis. (Expected 1,2, or 3; Got %d) Failing.",
		    uiNumAxis);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	//
	// Retrieve expected number of frames for this kind of test case
	//
	uiNumDesiredFrames = NumTransformFramesByIters[uiNumAxis];

	if (FAILED(hr = GetPermutationSpecs(uiNumAxis,          // UINT uiNumIters,
	                                    uiNumDesiredFrames, // UINT uiMaxIter,
	                                    &uiTotalFrames,     // UINT *puiNumStepsTotal,
	                                    NULL)))
	{
		DebugOut(L"GetPermutationSpecs failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	//
	// Confirm that test case can generate exactly the desired number of frames
	//
	if (uiNumDesiredFrames != uiTotalFrames)
	{
		DebugOut(
		    L"Unexpected number of frames. (Expected %d; Got %d) Failing.",
		    uiNumDesiredFrames,
		    uiTotalFrames);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = GenerateSphere( pDevice,           // LPDIRECT3DMOBILEDEVICE pDevice,
	                                &pVBSphere,        // LPDIRECT3DMOBILEVERTEXBUFFER *ppVB,
	                                Format,            // D3DMFORMAT Format,
	                                &pIBSphere,        // LPDIRECT3DMOBILEINDEXBUFFER *ppIB, 
	                                uiNumDivisions,    // const int nDivisions
	                                &PrimType,         // D3DMPRIMITIVETYPE *pPrimType
	                                &uiPrimCount,      // PUINT puiPrimCount
	                                &uiNumVertices)))  // PUINT puiNumVertices
	{
		DebugOut(L"GenerateSphere failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	uiFrame = uiFrameNumber;

	if (FAILED(hr = SetTransformDefaults(pDevice))) // LPDIRECT3DMOBILEDEVICE pDevice
	{
		DebugOut(L"SetTransformDefaults failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	switch(uiNumAxis)
	{
	case 1:
		if (FAILED(hr = OneAxisPermutations(uiFrame,                  // UINT uiFrame,
			                                D3DQA_TRANSLATEFACTOR_MIN,// float fMin,
			                                D3DQA_TRANSLATEFACTOR_MAX,// float fMax,
			                                uiNumDesiredFrames,       // UINT uiMaxIters,
			                                &fAxis1)))                // float *pfAxis,
		{
			DebugOut(L"OneAxisPermutations failed. (hr = 0x%08x) Failing.", hr);
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		// Default all axis to no translation
		fX = fY = fZ = 0.0f;

		if (UsesAxis(D3DQA_TRANSLATEAXIS_X, TranslateType))
			fX = fAxis1;

		if (UsesAxis(D3DQA_TRANSLATEAXIS_Y, TranslateType))
			fY = fAxis1;

		if (UsesAxis(D3DQA_TRANSLATEAXIS_Z, TranslateType))
			fZ = fAxis1;

		if (false == GetTranslate(TranslateType,    // D3DQA_TranslateType rType,
			                      fX,               // const float fXTranslate,
			                      fY,               // const float fYTranslate,
			                      fZ,               // const float fZTranslate,
			                      &TranslateMatrix))// D3DMMATRIX* const TranslateMatrix,
		{
			DebugOut(L"GetTranslate failed. Failing.");
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		break;
	case 2:
		if (FAILED(hr = TwoAxisPermutations(uiFrame,                  // UINT uiFrame,
			                                D3DQA_TRANSLATEFACTOR_MIN,// float fMin,
			                                D3DQA_TRANSLATEFACTOR_MAX,// float fMax,
			                                uiNumDesiredFrames,       // UINT uiMaxIters,
			                                &fAxis1,                  // float *pfAxis1,
			                                &fAxis2)))                // float *pfAxis2,
		{
			DebugOut(L"TwoAxisPermutations failed. (hr = 0x%08x) Failing.", hr);
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		// Default all axis to no translation
		fX = fY = fZ = 0.0f;

		if (false == UsesAxis(D3DQA_TRANSLATEAXIS_X, TranslateType))
		{
			fY = fAxis1;
			fZ = fAxis2;
		}
		else if (false == UsesAxis(D3DQA_TRANSLATEAXIS_Y, TranslateType))
		{
			fX = fAxis1;
			fZ = fAxis2;
		}
		else if (false == UsesAxis(D3DQA_TRANSLATEAXIS_Z, TranslateType))
		{
			fX = fAxis1;
			fY = fAxis2;
		}
		else
		{
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		if (false == GetTranslate(TranslateType,    // D3DQA_TranslateType rType,
			                      fX,               // const float fXTranslate,
			                      fY,               // const float fYTranslate,
			                      fZ,               // const float fZTranslate,
			                      &TranslateMatrix))// D3DMMATRIX* const TranslateMatrix,
		{
			DebugOut(L"GetTranslate failed. Failing.");
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		break;
	case 3:
		if (FAILED(hr = ThreeAxisPermutations(uiFrame,                  // UINT uiFrame,
			                                  D3DQA_TRANSLATEFACTOR_MIN,// float fMin,
			                                  D3DQA_TRANSLATEFACTOR_MAX,// float fMax,
			                                  uiNumDesiredFrames,       // UINT uiMaxIters,
			                                  &fX,                      // float *pfX,
			                                  &fY,                      // float *pfY,
			                                  &fZ )))                   // float *pfZ
		{
			DebugOut(L"ThreeAxisPermutations failed. (hr = 0x%08x) Failing.", hr);
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		if (false == GetTranslate(TranslateType,    // D3DQA_TranslateType rType,
			                      fX,               // const float fXTranslate,
			                      fY,               // const float fYTranslate,
			                      fZ,               // const float fZTranslate,
			                      &TranslateMatrix))// D3DMMATRIX* const TranslateMatrix,
		{
			DebugOut(L"GetTranslate failed. Failing.");
			iTestResult = TPR_FAIL;
			goto cleanup;
		}

		break;
	default:
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = pDevice->SetTransform(TransMatrix,  // D3DMTRANSFORMSTATETYPE State,
		                                  &TranslateMatrix, D3DMFMT_D3DMVALUE_FLOAT))) // CONST D3DMMATRIX *pMatrix
	{
		DebugOut(L"SetTransform failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}
	

	//
	// Clear the backbuffer and the zbuffer
	//
	pDevice->Clear( 0, NULL, D3DMCLEAR_TARGET|D3DMCLEAR_ZBUFFER,
						D3DMCOLOR_XRGB(0,0,0), 1.0f, 0 );

	if (FAILED(hr = pDevice->BeginScene()))
	{
		DebugOut(L"BeginScene failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = pDevice->DrawIndexedPrimitive(
		                           PrimType,     // D3DMPRIMITIVETYPE Type,
		                           0,            // INT BaseVertexIndex,
		                           0,            // UINT MinIndex,
		                           uiNumVertices,// UINT NumVertices,
		                           0,            // UINT StartIndex,
		                           uiPrimCount)))// UINT PrimitiveCount
	{
		DebugOut(L"DrawIndexedPrimitive failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = pDevice->EndScene()))
	{
		DebugOut(L"EndScene failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	if (FAILED(hr = pDevice->Present(NULL, NULL, NULL, NULL)))
	{
		DebugOut(L"Present failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}

	//
	// Flush the swap chain and capture a frame
	//
	if (FAILED(hr = DumpFlushedFrame(pTestCaseArgs, // LPTESTCASEARGS pTestCaseArgs
	                                 0,             // UINT uiFrameNumber,
	                                 NULL)))        // RECT *pRect = NULL
	{
		DebugOut(L"DumpFlushedFrame failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
		goto cleanup;
	}



cleanup:

	if (FAILED(hr = pDevice->SetIndices(NULL)))
	{
		DebugOut(L"SetIndices failed. (hr = 0x%08x) Failing.", hr);
		iTestResult = TPR_FAIL;
	}

	if (pVBSphere)
		pVBSphere->Release();

	if (pIBSphere)
		pIBSphere->Release();

	return iTestResult;
}


