//-----------------------------------------------------------------------------
// File: TVCalibration.cpp
//
// Desc: This sample is a standalone program used to do basic calibration on a
//       TV. It supplies a set of on-screen instructions to ensure that the
//       TV is set to optimimum output settings.
//
// Hist: 12.02.02 - Ported from some E3 TV calibration code
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------



int t = 0;
#include <dsound.h>
#include <dsstdfx.h>
#include <XBApp.h>
#include <XBFont.h>
#include <XBUtil.h>
#include <XBSound.h>
#include "XBResource.h"
extern IDirect3DDevice8 *Device;
extern HRESULT RenderGradientBackground( DWORD dwTopColor, 
                                         DWORD dwBottomColor );
extern XBGAMEPAD g_Gamepads[4];
extern FLOAT      m_fElapsedTime;
//-----------------------------------------------------------------------------
// Structures and Macros
//-----------------------------------------------------------------------------
struct SCREENVERTEX
{
    D3DXVECTOR4 pos;   // The transformed position for the vertex point.
    DWORD       color; // The vertex color. 
};
#define D3DFVF_SCREENVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)


struct D3DVERTEX
{
    D3DXVECTOR3 p;           // position
    D3DCOLOR    c;           // color
};
#define D3DFVF_D3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)


struct D3DVERTEX_TEX
{
    D3DXVECTOR3 p;           // position
    D3DCOLOR    c;           // color
    FLOAT       tu, tv;     // texture
};
#define D3DFVF_D3DVERTEX_TEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)


enum State
{
   START,
   STAGE1,
   STAGE2,
   STAGE3,
   STAGE4,
   ENDSTAGE
};

// Constants to define our world space
#define XMIN -10
#define XMAX 10
#define ZMIN -10
#define ZMAX 10
#define YMIN 0
#define YMAX 5


// Some colors
#define SEMITRANS_BLACK 0x40000000
#define BLACK           0xff000000
#define WHITE           0xffffffff
#define YELLOW          0xffffff00
#define RED             0xffff0000
#define DARK_RED        0xff500000
#define DARK_GREEN      0xff008000

extern LPDIRECTSOUND8          m_pDSound;              // DirectSound object


//-----------------------------------------------------------------------------
// Name: class CXBoxSample
// Desc: Application class. The base class provides just about all the
//       functionality we want, so we're just supplying stubs to interface with
//       the non-C++ functions of the app.
//-----------------------------------------------------------------------------

    // Packed resources
    CXBPackedResource*       tvm_xprResource;

    // Font
    CXBFont*                 tvm_Font;

    // Current display state
    enum State              m_eCurrentState;

    // Track last button pressed
    INT                     m_iLastButton;

    // Geometry
    LPDIRECT3DTEXTURE8      m_pTestPatternTexture;
    
    // Geometry for floor, source, and listener
    //D3DVERTEX               m_pFloorVertices[4];    // Quad for the floor
    //D3DVERTEX_TEX           m_pSourceVertices[4];   // Quad for the source
    //D3DVERTEX               m_pListenerVertices[4]; // Quad for the listener
    //LPDIRECT3DVERTEXBUFFER8 m_pGridVB;              // Lines to grid the floor
    //LPDIRECT3DTEXTURE8      m_pSpeakerTexture;

    // Sound variables
    //CWaveFile               m_wfSound;              // Wave file
    //LONG                    m_lVolumePercent;       // Current volume
    
    //LPDIRECTSOUNDBUFFER8    m_pDSBuffer;            // DirectSoundBuffer
    //BYTE*                   m_pSampleData;          // Sample data from wav

    // Sound source and listener positions
    //D3DXVECTOR3             m_vSourcePosition;      // Source position vector
    //D3DXVECTOR3             m_vListenerPosition;    // Listener position vector

    // Transform matrices
    D3DXMATRIX              m_matWorld;             // World transform
    D3DXMATRIX              m_matView;              // View transform
    D3DXMATRIX              m_matProj;              // Projection transform




//-----------------------------------------------------------------------------
// Name: main()
// Desc: Entry point to the program.
//-----------------------------------------------------------------------------
//VOID __cdecl main()
//{
//    CXBoxSample xbApp;
//    if( FAILED( xbApp.Create() ) )
////        return;
//    xbApp.Run();
//}



	void clearTV() {
		if(tvm_Font) {
			delete tvm_Font;
			tvm_Font = 0;
		}
		if(tvm_xprResource) {
			delete tvm_xprResource;
			tvm_xprResource = 0;
		}
		if(m_pTestPatternTexture) {
			m_pTestPatternTexture->Release();
			m_pTestPatternTexture = NULL;
		}
	}

	void setupTV() {
		clearTV();
		tvm_Font = new CXBFont();
		tvm_Font->Create( "Font.xpr" );
		tvm_xprResource = new CXBPackedResource();
		tvm_xprResource->Create( "Resource.xpr" );
		m_pTestPatternTexture = tvm_xprResource->GetTexture( "TestPattern" );
	}

	
//-----------------------------------------------------------------------------
// Name: CXBoxSample()
// Desc: Application constructor. Sets attributes for the app.
//-----------------------------------------------------------------------------
void initTVVars()
            
{
    m_iLastButton       = XINPUT_GAMEPAD_A;
    m_eCurrentState     = START;

    m_pTestPatternTexture = NULL;

   // m_pGridVB           = NULL;
//    m_pSpeakerTexture   = NULL;

//    m_lVolumePercent    = 100;
   // m_pSampleData       = NULL;
  //  m_vSourcePosition   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  //  m_vListenerPosition = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

	  // Create the font
	setupTV();




//    m_pSpeakerTexture     = tvm_xprResource.GetTexture( "Speaker" );

	// Create our vertex buffers
//    Device->CreateVertexBuffer( 2 * ( (ZMAX-ZMIN+1) + (XMAX-XMIN+1) ) * sizeof(D3DVERTEX), 0, 0, 0, &m_pGridVB );

}




//-----------------------------------------------------------------------------
// Name: Initialize()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT tvInitialize()
{
    m_eCurrentState = START;
	t = 1;

    // Set the transform matrices
    D3DXVECTOR3 vEyePt      = D3DXVECTOR3( XMIN, 45.0f,  ZMAX / 2.0f );
    D3DXVECTOR3 vLookatPt   = D3DXVECTOR3( XMIN,  0.0f,  ZMAX / 2.0f );
    D3DXVECTOR3 vUpVec      = D3DXVECTOR3( 0.0f,  0.0f,  1.0f );
    D3DXMatrixIdentity( &m_matWorld );
    D3DXMatrixLookAtLH( &m_matView, &vEyePt, &vLookatPt, &vUpVec );
    D3DXMatrixPerspectiveFovLH( &m_matProj, D3DX_PI/4, 4.0f/3.0f, 1.0f, 10000.0f );
    Device->SetTransform( D3DTS_WORLD, &m_matWorld );
    Device->SetTransform( D3DTS_VIEW, &m_matView );
    Device->SetTransform( D3DTS_PROJECTION, &m_matProj );

    //------------------------  
    // Sound stuff
    //------------------------  
    
    // Create DirectSound
   // if( FAILED( DirectSoundCreate( NULL, &m_pDSound, NULL ) ) )
    //    return E_FAIL;

    // Note: If the application doesn't care about vertical HRTF positioning,
    //       calling DirectSoundUseLightHRTF() can save about 60k of memory.
    return 0;
}




//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame, the call is the entry point for animating
//       the scene. As this code only changes text, there is no real animation
//-----------------------------------------------------------------------------
HRESULT tvFrameMove()
{
//    D3DXVECTOR3    vListenerOld = m_vListenerPosition;
//    D3DXVECTOR3    vSourceOld   = m_vSourcePosition;

    if( g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_A] > 0 )
    {
		if(t == 1) {
			m_iLastButton = XINPUT_GAMEPAD_A;
			t = 0; 
			return 0;
		}

        if( m_iLastButton != XINPUT_GAMEPAD_A )
        {
            m_iLastButton = XINPUT_GAMEPAD_A;

            switch(m_eCurrentState)
            {
                case START:
                    m_eCurrentState = STAGE1;
                    break;

                case STAGE1:
                    m_eCurrentState = STAGE2;
                    break;

                case STAGE2:
                    m_eCurrentState = STAGE3;
                    break;

                case STAGE3:
                    m_eCurrentState = START;
                    break;

                //case STAGE4:
                //    m_eCurrentState = START;
                //    break;
                default:
                    m_eCurrentState = START;
            }
        }
    }
    else
    {
        m_iLastButton = !XINPUT_GAMEPAD_A;
    }

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: DrawLine()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawLine( FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2,
                            DWORD dwStartColor, DWORD dwEndColor )
{
    SCREENVERTEX v[2];
    v[0].pos = D3DXVECTOR4( x1, y1, 0.5f, 1.0f );   v[0].color = dwStartColor;
    v[1].pos = D3DXVECTOR4( x2, y2, 0.5f, 1.0f );   v[1].color = dwEndColor;
    
    // Render the line
    Device->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
    Device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );

    Device->SetVertexShader( D3DFVF_SCREENVERTEX) ;
    Device->DrawPrimitiveUP( D3DPT_LINELIST, 1, v, sizeof(SCREENVERTEX) );
}




//-----------------------------------------------------------------------------
// Name: DrawThickLine()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawThickLine( FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2,
                                 DWORD dwColor, FLOAT fWidth )
{
    // Determine offsets for the black line
    D3DXVECTOR3 vc( y2-y1, -x2+x1, 0.0f );
    D3DXVec3Normalize( &vc, &vc );
    D3DXVECTOR3 vc1 = vc * (fWidth/2+1.0f);
    D3DXVECTOR3 vc2 = vc * (fWidth/2);
    
    // Draw the line
    Device->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
    Device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
    Device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_DIFFUSE ) ;
    Device->Begin( D3DPT_QUADLIST );

    Device->SetVertexDataColor( D3DVSDE_DIFFUSE, BLACK );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x1-vc1.x, y1-vc1.y, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x1+vc1.x, y1+vc1.y, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x2+vc1.x, y2+vc1.y, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x2-vc1.x, y2-vc1.y, 0.0f, 0.0f );

    Device->SetVertexDataColor( D3DVSDE_DIFFUSE, dwColor );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x1-vc2.x, y1-vc2.y, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x1+vc2.x, y1+vc2.y, 0.0f, 0.0f );
    Device->SetVertexDataColor( D3DVSDE_DIFFUSE, dwColor );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x2+vc2.x, y2+vc2.y, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, x2-vc2.x, y2-vc2.y, 0.0f, 0.0f );
    
    Device->End();
}




//-----------------------------------------------------------------------------
// Name: DrawRectOutline()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawRectOutline( FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, 
                                   DWORD dwColor )
{
    tvDrawLine( x1, y1, x1, y2, dwColor, dwColor );
    tvDrawLine( x1, y1, x2, y1, dwColor, dwColor );
    tvDrawLine( x2, y1, x2, y2, dwColor, dwColor );
    tvDrawLine( x1, y2, x2, y2, dwColor, dwColor );
}




//-----------------------------------------------------------------------------
// Name: DrawRect()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawRect( FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, 
                            DWORD dwStartColor, DWORD dwEndColor )
{
    SCREENVERTEX v[4];
    v[0].pos = D3DXVECTOR4( x1-0.5f, y1-0.5f, 1.0f, 1.0f );  v[0].color = dwStartColor;
    v[1].pos = D3DXVECTOR4( x2-0.5f, y1-0.5f, 1.0f, 1.0f );  v[1].color = dwStartColor;
    v[2].pos = D3DXVECTOR4( x1-0.5f, y2-0.5f, 1.0f, 1.0f );  v[2].color = dwEndColor;
    v[3].pos = D3DXVECTOR4( x2-0.5f, y2-0.5f, 1.0f, 1.0f );  v[3].color = dwEndColor;
    
    // Render the rectangle
    Device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE );
    Device->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
    Device->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
    Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

    Device->SetVertexShader( D3DFVF_SCREENVERTEX );
    Device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, v, sizeof(SCREENVERTEX) );
}




//-----------------------------------------------------------------------------
// Name: DrawTextBox()
// Desc: Renders text in an outlined, semi-transparent box
//-----------------------------------------------------------------------------
VOID tvDrawTextBox( FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, 
                               WCHAR* strText )
{
    tvDrawRect( x1, y1, x2, y2, SEMITRANS_BLACK, SEMITRANS_BLACK );
    tvDrawRectOutline( x1, y1, x2, y2, BLACK );
    tvm_Font->DrawText( x1+5, y1+5, WHITE, strText );
}




//-----------------------------------------------------------------------------
// Name: DrawTestPattern()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawTestPattern()
{
    // Set state for rendering the quad
    Device->SetTexture( 0, m_pTestPatternTexture );
    Device->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
    Device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    Device->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
    Device->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
    Device->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
    Device->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
    Device->SetRenderState( D3DRS_ZENABLE, FALSE ); 
    Device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

    Device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 );
    Device->Begin( D3DPT_QUADLIST );
    Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX,   0.0f-0.5f,   0.0f-0.5f, 0.0f, 1.0f );
    Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 640.0f, 0.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, 640.0f-0.5f,   0.0f-0.5f, 0.0f, 1.0f );
    Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 640.0f, 480.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX, 640.0f-0.5f, 480.0f-0.5f, 0.0f, 1.0f );
    Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0.0f, 480.0f );
    Device->SetVertexData4f( D3DVSDE_VERTEX,   0.0f-0.5f, 480.0f-0.5f, 0.0f, 1.0f );
    Device->End();
}




//-----------------------------------------------------------------------------
// Name: DrawStartScreen()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawStartScreen()
{
    // Draw the test pattern
    tvDrawTestPattern();

    // Stop the sound if it is playing
//    m_pDSBuffer->Stop();

    // Render instructions in an outlined, semi-transparent box
    tvDrawTextBox( 64, 50, 576, 135, L"Turn up the CONTRAST to full, then turn up the\n"
                                   L"BRIGHTNESS until you can see five separate\n"
                                   L"black regions between these lines." );

    // Draw lines
    tvDrawThickLine( 468, 136, 468, 340, WHITE, 2.0f );
    tvDrawThickLine( 336, 340, 600, 340, WHITE, 2.0f );
    tvDrawThickLine( 336, 340, 336, 360, WHITE, 2.0f );
    tvDrawThickLine( 600, 340, 600, 360, WHITE, 2.0f );
}




//-----------------------------------------------------------------------------
// Name: DrawStage1Screen()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawStage1Screen()
{
    // Draw the test pattern
    tvDrawTestPattern();

    // Render instructions in an outlined, semi-transparent box
    tvDrawTextBox( 64, 50, 576, 135, L"Now reduce the BRIGHTNESS until the gray bar\n"
                                   L"disappears, then turn the BRIGHTNESS back up\n"
                                   L"until it becomes just visible." );

    // Draw lines
    tvDrawThickLine( 536, 136, 536, 340, WHITE, 2.0f );
    tvDrawThickLine( 520, 340, 552, 340, WHITE, 2.0f );
    tvDrawThickLine( 520, 340, 520, 360, WHITE, 2.0f );
    tvDrawThickLine( 552, 340, 552, 360, WHITE, 2.0f );
}




//-----------------------------------------------------------------------------
// Name: DrawStage2Screen()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawStage2Screen()
{
    // Draw the test pattern
    tvDrawTestPattern();

    // Render instructions in an outlined, semi-transparent box
    tvDrawTextBox( 64, 50, 576, 160, L"Set the CONTRAST by lowering it until the edges\n"
                                   L"of the white bar look sharp, continue lowering\n"
                                   L"until white bar begins to look not-white, then turn\n"
                                   L"back up until white bar looks white again." );

    // Draw lines
    tvDrawThickLine( 173, 161, 173, 340, WHITE, 2.0f );
    tvDrawThickLine( 113, 340, 223, 340, WHITE, 2.0f );
    tvDrawThickLine( 113, 340, 113, 360, WHITE, 2.0f );
    tvDrawThickLine( 223, 340, 223, 360, WHITE, 2.0f );
}




//-----------------------------------------------------------------------------
// Name: DrawStage3Screen()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawStage3Screen()
{
    // Draw the test pattern
    tvDrawTestPattern();

    // Render instructions in an outlined, semi-transparent box
    tvDrawTextBox( 64, 50, 576, 110, L"Now adjust COLOR to minimize bleeding, using\n"
                                   L"the red bar as your main reference." );
}




//-----------------------------------------------------------------------------
// Name: DrawStage4Screen()
// Desc: 
//-----------------------------------------------------------------------------
VOID tvDrawStage4Screen()
{
	return;
}




//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Sets up render states, clears the viewport, and renders the scene.
//-----------------------------------------------------------------------------
HRESULT tvRender()
{
    // Depending on the app state, call one of the following methods
    switch( m_eCurrentState )
    {
        case START:
            tvDrawStartScreen();
            break;

        case STAGE1:
            tvDrawStage1Screen();
            break;
        
        case STAGE2:
            tvDrawStage2Screen();
            break;
        
        case STAGE3:
            tvDrawStage3Screen();
            break;
        
       // case STAGE4:
       //     tvDrawStage4Screen();
       //     break;
        
        case ENDSTAGE:
            break;
    }

    // Present the scene
    Device->Present( NULL, NULL, NULL, NULL );

    return S_OK;
}

void initTV() {
	tvInitialize();
}

void inputTV() {
	tvFrameMove();
}

void drawTV() {
	tvRender();
}



