// SDirectX.cpp: implementation of the SDirectX class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Simulator.h"
#include "SDirectX.h"
#include "SGDIRender.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

SDirectX::SDirectX()
{
    m_dwFogColor = 0x00b5b5ff;
    g_pFloorVB        = NULL;
	g_pRoofVB        = NULL;
	g_pWallVB        = NULL;

    int ToolbarOffset = 26;

    WindowSize.left = 10;
    WindowSize.right = 510;
    WindowSize.top = 10 + ToolbarOffset;
    WindowSize.bottom = 510 + ToolbarOffset;   

    Enabled = false;

    WallStruct.WallPtr = NULL;
    WallStruct.RoofPtr = NULL;
    WallStruct.WallBufferCount = 0;
	WallStruct.FloorBufferCount = 0;
	WallStruct.RoofBufferCount = 0;
    WallStruct.isReady = false;

    OldMousePoint.x = -1;
    OldMousePoint.y = -1;
 
    Robot.Valid = false;
	Robot.SonarValid = false;
    Robot.Mesh = NULL;
	Robot.Sonar = NULL;
	Robot.ModelOffCenterZ = 2.5;

	m_pFloorTexture = NULL;
	m_pTreadTexture = NULL;
	m_pWallTexture = NULL;
	m_pJFPetersTexture = NULL;

	EnableAltTexture = false;

    ResetView();




}

SDirectX::~SDirectX()
{
  if (g_pFloorVB != NULL)
      g_pFloorVB->Release();

  if (g_pWallVB != NULL)
	  g_pWallVB->Release();

  if (g_pRoofVB != NULL)
      g_pRoofVB->Release();

  if (g_pModelVB != NULL)
      g_pModelVB->Release();

  SAFE_DELETE( Robot.Mesh );

  SAFE_DELETE( Robot.Sonar );

  SAFE_RELEASE(m_pFloorTexture);

  SAFE_RELEASE(m_pTreadTexture);

  SAFE_RELEASE(m_pWallTexture);

  SAFE_RELEASE(m_pJFPetersTexture);

  Cleanup3DEnvironment();

  RenderResetWalls();

}

void SDirectX::Create()
{
    char windowname[40]; 

    // Register the windows class
      /*  WNDCLASS wndClass = { 0, WndProc, 0, 0, AfxGetInstanceHandle(),
                              LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
                              LoadCursor( NULL, IDC_ARROW ),
                              (HBRUSH)GetStockObject(WHITE_BRUSH),
                              NULL, _T("D3D Window") };
        RegisterClass( &wndClass );*/

         strcpy(windowname,//AfxRegisterWndClass(NULL,NULL,NULL,NULL));

            AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		        ::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL));

        // Set the window's initial style
        m_dwWindowStyle = WS_THICKFRAME
                          |WS_VISIBLE| WS_CHILD ;

        if (!Enabled)
        {
            m_dwWindowStyle &= ~WS_VISIBLE;
            m_dwWindowStyle |= WS_DISABLED;
        }



    // Create the render window 
        FrameWindow.CreateEx(WS_EX_TOPMOST  ,windowname,"Hello",m_dwWindowStyle,WindowSize,FramePtr,NULL,NULL);

     m_hWnd =FrameWindow.m_hWnd;


  
    CD3DApplication::Create( AfxGetInstanceHandle() );

 

    // create the vertex buffer used for the walls
     if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAXVERTEXCOUNT*sizeof(VERTEX),
													   D3DUSAGE_DYNAMIC ,
													   VERTEX_TYPE,
													   D3DPOOL_DEFAULT,
													   &g_pFloorVB 
													   ) )) 
                                                       AfxMessageBox("Failed Vertex Buffer");

     if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAXVERTEXCOUNT*sizeof(VERTEX),
												   D3DUSAGE_DYNAMIC ,
												   VERTEX_TYPE,
												   D3DPOOL_DEFAULT,
												   &g_pWallVB 
												   ) )) 
                                                   AfxMessageBox("Failed model Vertex Buffer");

	 if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAXVERTEXCOUNT*sizeof(VERTEX),
												   D3DUSAGE_DYNAMIC ,
												   VERTEX_TYPE,
												   D3DPOOL_DEFAULT,
												   &g_pRoofVB 
												   ) )) 
                                                   AfxMessageBox("Failed model Vertex Buffer");



	  if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAXVERTEXCOUNT*sizeof(VERTEX),
												   D3DUSAGE_DYNAMIC ,
												   VERTEX_TYPE,
												   D3DPOOL_DEFAULT,
												   &g_pModelVB 
												   ) )) 
                                                   AfxMessageBox("Failed model Vertex Buffer");


     LoadModels();

	     // Create the floor texture
    if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T(FLOORTEXTURE),
                                       &m_pFloorTexture, D3DFMT_R5G6B5 ) ) )
		AfxMessageBox("Warning failure to load floor texture");

	if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T(TREADTEXTURE),
                                       &m_pTreadTexture, D3DFMT_R5G6B5 ) ) )
		AfxMessageBox("Warning failure to load tread texture");

	if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T(WALLTEXTURE),
                                       &m_pWallTexture, D3DFMT_R5G6B5 ) ) )
		AfxMessageBox("Warning failure to load wall texture");

	if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T(JFPETERSTEXTURE),
                                       &m_pJFPetersTexture, D3DFMT_R5G6B5 ) ) )
		AfxMessageBox("Warning failure to load JFPeters texture");



	SDirectXTread::TREADINFO Tread;

	Tread.Width = 50;
	Tread.Length = 190;
	Tread.Radius = 20;
	Tread.NumofTreads = 50;
	Tread.CenterPoint.x = 0;
	Tread.CenterPoint.y = 0;
	Tread.CenterPoint.z = 0;

	// create the treads
	Robot.RightTread.Create(Tread,m_pd3dDevice);
	Robot.LeftTread.Create(Tread,m_pd3dDevice);




}

/************************************************************************
* void RenderFormWall(VERTEX *pVertex, FPoint Start, FPoint End)
*
* PURPOSE
* Loads a vertex buffer with wall coordinates
*************************************************************************/
void SDirectX::RenderFormWall(VERTEX* pVertex,FPoint Start, FPoint End)
{
	float height = DEFAULTHEIGHT;

	// yellow red scheme
//	DWORD Color1 = 0xffff0000;
//	DWORD Color2 = 0xffffff00;

	DWORD Color1 = 0xff00afff;
	DWORD Color2 = 0xff0020ff;

//	DWORD Color1 = 0xffffffff;
//	DWORD Color2 = 0xffffffff;

	pVertex[0].position.x = Start.x;
	pVertex[0].position.y = 0.0f;
	pVertex[0].position.z = Start.y;
	pVertex[0].color = Color1;
	pVertex[0].tu = 1.0f;
	pVertex[0].tv = 1.0f;

	pVertex[1].position.x = End.x;
	pVertex[1].position.y = 0.0f;
	pVertex[1].position.z = End.y;
	pVertex[1].color = Color1;
	pVertex[1].tu = 0.0f;
	pVertex[1].tv = 1.0f;

	pVertex[2].position.x = End.x;
	pVertex[2].position.y = height;
	pVertex[2].position.z = End.y;
	pVertex[2].color = Color2;
	pVertex[2].tu = 0.0f;
	pVertex[2].tv = 0.0f;

	pVertex[3].position.x = Start.x;
	pVertex[3].position.y = 0.0f;
	pVertex[3].position.z = Start.y;
	pVertex[3].color = Color1;
	pVertex[3].tu = 1.0f;
	pVertex[3].tv = 1.0f;

	pVertex[4].position.x = End.x;
	pVertex[4].position.y = height;
	pVertex[4].position.z = End.y;
	pVertex[4].color = Color2;
	pVertex[4].tu = 0.0f;
	pVertex[4].tv = 0.0f;

	pVertex[5].position.x = Start.x;
	pVertex[5].position.y = height;
	pVertex[5].position.z = Start.y;
	pVertex[5].color = Color2;
	pVertex[5].tu = 1.0f;
	pVertex[5].tv = 0.0f;

}

/************************************************************************
* void RenderFormBumper(VERTEX* pVertex,FPoint Start, FPoint End);
*
* PURPOSE
* Loads a vertex buffer with bumper coordinates
*************************************************************************/
void SDirectX::RenderFormBumper(VERTEX* pVertex,FPoint Start, FPoint End)
{
    float minHeight = 0;
	float height = DEFAULTBUMPERHEIGHT/5;

	pVertex[0].position.x = Start.x;
	pVertex[0].position.y = minHeight;
	pVertex[0].position.z = Start.y;
	pVertex[0].color = 0xffff0000;
//	pVertex[0].tu = 0.0f;
//	pVertex[0].tv = 0.0f;

	pVertex[1].position.x = End.x;
	pVertex[1].position.y = minHeight;
	pVertex[1].position.z = End.y;
	pVertex[1].color = 0xffff0000;
//	pVertex[1].tu = 1.0f;
//	pVertex[1].tv = 0.0f;

	pVertex[2].position.x = End.x;
	pVertex[2].position.y = height;
	pVertex[2].position.z = End.y;
	pVertex[2].color = 0xffffff00;
//	pVertex[2].tu = 1.0f;
//	pVertex[2].tv = 1.0f;

	pVertex[3].position.x = Start.x;
	pVertex[3].position.y = minHeight;
	pVertex[3].position.z = Start.y;
	pVertex[3].color = 0xffff0000;
//	pVertex[3].tu = 0.0f;
//	pVertex[3].tv = 0.0f;

	pVertex[4].position.x = End.x;
	pVertex[4].position.y = height;
	pVertex[4].position.z = End.y;
	pVertex[4].color = 0xffffff00;
//	pVertex[4].tu = 1.0f;
//	pVertex[4].tv = 1.0f;

	pVertex[5].position.x = Start.x;
	pVertex[5].position.y = height;
	pVertex[5].position.z = Start.y;
	pVertex[5].color = 0xffffff00;
//	pVertex[5].tu = 0.0f;
//	pVertex[5].tv = 1.0f;

}

/************************************************************************
* void RenderFormWall(VERTEX *pVertex, FPoint Start, FPoint End)
*
* PURPOSE
* Loads a vertex buffer with wall coordinates
*************************************************************************/
void SDirectX::RenderFormFloor(VERTEX* pVertex,FPoint Start, FPoint End, DWORD Color)
{
	float height = DEFAULTHEIGHT;

	pVertex[0].position.x = Start.x;
	pVertex[0].position.y = 0.0f;
	pVertex[0].position.z = Start.y;
	pVertex[0].color = Color;
	pVertex[0].tu = 0.0f;
	pVertex[0].tv = 0.0f;

	pVertex[1].position.x = End.x;
	pVertex[1].position.y = 0.0f;
	pVertex[1].position.z = End.y;
	pVertex[1].color = Color;
	pVertex[1].tu = 1.0f;
	pVertex[1].tv = 1.0f;

	pVertex[2].position.x = Start.x;
	pVertex[2].position.y = 0.0f;
	pVertex[2].position.z = End.y;
	pVertex[2].color = Color;
	pVertex[2].tu = 0.0f;
	pVertex[2].tv = 1.0f;

	pVertex[3].position.x = Start.x;
	pVertex[3].position.y = 0.0f;
	pVertex[3].position.z = Start.y;
	pVertex[3].color = Color;
	pVertex[3].tu = 0.0f;
	pVertex[3].tv = 0.0f;

	pVertex[4].position.x = End.x;
	pVertex[4].position.y = 0.0f;
	pVertex[4].position.z = End.y;
	pVertex[4].color = Color;
	pVertex[4].tu = 1.0f;
	pVertex[4].tv = 1.0f;


	pVertex[5].position.x = End.x;
	pVertex[5].position.y = 0.0f;
	pVertex[5].position.z = Start.y;
	pVertex[5].color = Color;
	pVertex[5].tu = 1.0f;
	pVertex[5].tv = 0.0f;

	WallStruct.FloorBufferCount +=2;

}

// this functions launches the base classes to start rendering
void SDirectX::OnRender(FPoint ModelCenter, float ModelAngle)
{
    TheCamera.ModelCenter = ModelCenter;
    TheCamera.ModelAngle = ModelAngle;
    Render3DEnvironment();

}

// called by the base class after some stuff has been set up
// this is where all my stuff goes in.
HRESULT SDirectX::Render()
{ 
    if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
    {

        // Turn off culling, so we see the front and back of the triangle
        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );        

        // put is some depth buffering
        m_pd3dDevice->SetRenderState(D3DRS_ZENABLE , D3DZB_TRUE);      

        // Turn on some lighting options, done for the meshes
        m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,   TRUE );
        //m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
		 m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE  , D3DSHADE_GOURAUD );

  


        // Clear the viewport
        if (m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER ,
                           RGB(255,255,255), 1.0f, 0L ) != D3D_OK )
                           AfxMessageBox("Clear Problem");

        	    ////////////////////////////
	    // Set the Camera View (Usually this shouldn't be done in the Render Loop, but intialized only once)

    //	count = count + 0.5f;	
	    
	    // Do world transform (simply an identity)
	    D3DXMATRIX matrixWorld;
	    D3DXMatrixIdentity(&matrixWorld);
        // scale down the 12800 by 12800 world by a factor of 1000
        D3DXMatrixScaling(&matrixWorld,0.001f,0.001f,0.001f);
	    m_pd3dDevice->SetTransform( D3DTS_WORLD, &matrixWorld );

        // adjust the position
        AdjustCameraPosition();

	    // View Transform
	    D3DXMATRIX matrixView;
	    D3DXMatrixLookAtLH( &matrixView, 
						    &TheCamera.Eye,	// Current camera position
                       	    &TheCamera.At ,	// Look at position
                            &TheCamera.Orientation) ;// Orientation 

      //  D3DXMatrixRotationY(&matrixView,TheCamera.ya);
       // D3DXMatrixRotationX(&matrixView,TheCamera.xa);

	    m_pd3dDevice->SetTransform( D3DTS_VIEW, &matrixView );

	    // Projection Transform
	    D3DXMATRIX matProj;
	    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 0.001f, 100.0f );
	    m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); 

		 //   m_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);	// Wireframe for dubugging

				// do the lighting



	/*	D3DLIGHT8 d3dLight;
		HRESULT   hr;

		 float NScaling = 0.0001f;
		 float IScaling = 1000*NScaling;


		// Initialize the structure.
		ZeroMemory(&d3dLight, sizeof(D3DLIGHT8));

		// Set up a white point light.
		d3dLight.Type = D3DLIGHT_POINT;
		d3dLight.Diffuse.r  = 1.0f;
		d3dLight.Diffuse.g  = 0.0f;
		d3dLight.Diffuse.b  = 0.0f;
		d3dLight.Ambient.r  = 1.0f;
		d3dLight.Ambient.g  = 0.0f;
		d3dLight.Ambient.b  = 0.0f;
		d3dLight.Specular.r = 1.0f;
		d3dLight.Specular.g = 0.0f;
		d3dLight.Specular.b = 0.0f;

		d3dLight.Position.x = TheCamera.ModelCenter.x/1000;
		d3dLight.Position.y = 0.2f;
		d3dLight.Position.z = TheCamera.ModelCenter.y/1000;

		// Don't attenuate.
		d3dLight.Attenuation0 = 200.0f; 
		d3dLight.Attenuation1 = 1.0f; 
		d3dLight.Attenuation2 = 300.2f; 
		d3dLight.Range      = 0.28f;

		// Set the property information for the first light.
		hr = m_pd3dDevice->SetLight(0, &d3dLight);
		
		if (FAILED(hr))
		{
			AfxMessageBox("lighting failed");
			// Code to handle the error goes here.
		}
		else
		{
			if( m_pd3dDevice->LightEnable(0,TRUE) == D3DERR_INVALIDCALL)
			{
				int asdf;
				asdf = 34;
			}

		}*/

 	    //////////////////////////
	    // Set the stream source
		 m_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);  
        if (WallStruct.isReady)
        {

			m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
			//m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff);

			if (EnableAltTexture)
			{
						
				// draw the floor
				m_pd3dDevice->SetTexture(0,m_pJFPetersTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pFloorVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.FloorBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);

				// draw the walls
				m_pd3dDevice->SetTexture(0,m_pJFPetersTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pWallVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.WallBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);

				// draw the roofs
				m_pd3dDevice->SetTexture(0,m_pJFPetersTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pRoofVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.RoofBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);
			}
			else
			{

			
				m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
				// draw the floor
				m_pd3dDevice->SetTexture(0,m_pFloorTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pFloorVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.FloorBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);

				// draw the walls
				m_pd3dDevice->SetTexture(0,m_pWallTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pWallVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.WallBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);

				// draw the roofs
				m_pd3dDevice->SetTexture(0,m_pWallTexture);
				m_pd3dDevice->SetStreamSource( 0, g_pRoofVB, sizeof(VERTEX) );
				m_pd3dDevice->SetVertexShader( VERTEX_TYPE ); 
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, WallStruct.RoofBufferCount);
				m_pd3dDevice->SetTexture(0,NULL);
			}

		}

		if (EnableAltTexture)
		{
			m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff);
			m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
		}
		else
		{
			m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff);
			m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
		}

        // render the model
        RenderModel();

						// a bit of ambient lighting
		m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff);
        m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

        // reset because model changes this
        D3DXMatrixIdentity(&matrixWorld);
        // scale down the 12800 by 12800 world by a factor of 1000
        D3DXMatrixScaling(&matrixWorld,0.001f,0.001f,0.001f);
	    m_pd3dDevice->SetTransform( D3DTS_WORLD, &matrixWorld );

        // add the models vertices to the buffer
        RenderSensors();



     
        m_pd3dDevice->EndScene();
    }
    else
    {
        AfxMessageBox("Scene problems");
    }

    return S_OK;

}


/************************************************************************
* Function RenderAddWall(FPoint Start, FPoint End)
*
* PURPOSE
* This function could be called by anyone during a directX rendering loop.  It creates
* a 3D wall out of a 2D line.
* USAGE
* Probably quadtree
* OUTPUT
* Internally adds some vertices to the vertex buffer.
*************************************************************************/
void SDirectX::RenderAddWall(FPoint Start, FPoint End)
{
    WallStructPtr NewPtr;

    NewPtr = new WALLSTRUCT;

    NewPtr->Start = Start;
    NewPtr->End = End;
    NewPtr->Type = Wall;
    NewPtr->Next = WallStruct.WallPtr;
    WallStruct.WallPtr = NewPtr;
    
     WallStruct.WallBufferCount += 2;
}

/************************************************************************
* Function RenderResetWall()
*
* PURPOSE
* This function reset the wall pointer structure
* USAGE
* Probably quadtree
* OUTPUT
* Internally clears the wall pointer
*************************************************************************/
void SDirectX::RenderResetWalls()
{
    WallStructPtr DeletePtr;

    while (WallStruct.WallPtr != NULL)
    {
        DeletePtr = WallStruct.WallPtr;
        WallStruct.WallPtr = WallStruct.WallPtr->Next;
        delete DeletePtr;
        DeletePtr = NULL;
    }

    while (WallStruct.RoofPtr != NULL)
    {
        DeletePtr = WallStruct.RoofPtr;
        WallStruct.RoofPtr = WallStruct.RoofPtr->Next;
        delete DeletePtr;
        DeletePtr = NULL;
    }

    WallStruct.WallPtr = NULL;
    WallStruct.RoofPtr = NULL;
    WallStruct.WallBufferCount = 0;
	WallStruct.RoofBufferCount = 0;
}

/************************************************************************
* Function RenderCreateWallVertixBuffer()
*
* PURPOSE
* To fill the wall vertix buffer based on whats in the wall linked list
* OUTPUT
* Internally, fills the wall vertix buffer
*************************************************************************/
void SDirectX::RenderCreateWallVertexBuffer()
{
    WallStruct.isReady = false;
    int NSplitFloor = 20;

   
    VERTEX* pVerticesFloor;
	VERTEX* pVerticesWall;
	VERTEX* pVerticesRoof;

	if( FAILED( g_pFloorVB->Lock(0, 0, (BYTE**)&pVerticesFloor, 0 ) ) )
    {
        AfxMessageBox("Vertex Failure 2");
        return;
    }

	if( FAILED( g_pWallVB->Lock(0, 0, (BYTE**)&pVerticesWall, 0 ) ) )
    {
        AfxMessageBox("Vertex Failure 1");
        return;
    }

	if( FAILED( g_pRoofVB->Lock(0, 0, (BYTE**)&pVerticesRoof, 0 ) ) )
    {
        AfxMessageBox("Vertex Failure 1");
        return;
    }

	VERTEX* pCurrVertexFloor = pVerticesFloor;
	VERTEX* pCurrVertexWall = pVerticesWall;
	VERTEX* pCurrVertexRoof = pVerticesRoof;

	WallStructPtr TraversePtr = WallStruct.WallPtr;  

    while (TraversePtr != NULL)
    {
        if (TraversePtr->Type == Wall)
        {
            RenderFormWall(pVerticesWall,TraversePtr->Start,TraversePtr->End);     
            pVerticesWall = pVerticesWall + 6;
        }
        else if (TraversePtr->Type == Floor)
        {
            
            for (int ix = 0; ix < NSplitFloor; ix++)
            {
                 for (int iy = 0; iy < NSplitFloor; iy++)
                 {
                     DWORD Color;
                    // create a checkboard pattern
                    if ((ix/2)*2 == ix)
                    {
                        if ((iy/2)*2 == iy)
                            Color = 0xf9ffffff;
                        else
                            Color = 0xfafffaf; // green
                    }
                    else
                    {
                        if ((iy/2)*2 != iy)
                            Color = 0xffffff9f;
                        else
                            Color = 0xfafffaf; // yellow
                    }
				//	Color = 0xffffff9f;
                    float Height = (TraversePtr->End.y - TraversePtr->Start.y)/NSplitFloor;
                    float Width = (TraversePtr->End.x - TraversePtr->Start.x)/NSplitFloor;

                    FPoint Start, End;

                    Start.x = TraversePtr->Start.x + Width*ix;
                    End.x = TraversePtr->Start.x + Width*(ix+1);

                    Start.y = TraversePtr->Start.y + Height*iy;
                    End.y = TraversePtr->Start.y + Height*(iy+1);				

                    RenderFormFloor(pCurrVertexFloor,Start,End,Color); 
                    pCurrVertexFloor = pCurrVertexFloor + 6;

                 }
            }   
        }
        
        TraversePtr = TraversePtr->Next;

    }     

    // do the roof afterward for zbuffering purposes
    TraversePtr = WallStruct.RoofPtr;  
    while (TraversePtr != NULL)
    {
        // it better be of type roof
        if (TraversePtr->Type == Roof)
        {
            RenderFormRoof(pCurrVertexRoof,TraversePtr->Start,TraversePtr->End,TraversePtr->Extra);
            pCurrVertexRoof = pCurrVertexRoof + 3;
        }           
        TraversePtr = TraversePtr->Next;
    }         
     

	g_pFloorVB->Unlock();
	g_pWallVB->Unlock();
	g_pRoofVB->Unlock();

    WallStruct.isReady = true;

}

/************************************************************************
* Function LoadWalls()
*
* PURPOSE
* Access the quadtree and get wall information from it.
*************************************************************************/
void SDirectX::LoadWalls()
{
    RenderResetWalls();

    MapPtr->DirectXCreateWallList();

    SQuadTree::WallList Wall;

    FRect MaxPoints;   
    MaxPoints.bottom = 0;
    MaxPoints.top = (float)99999999999;
    MaxPoints.left = (float)9999999999;
    MaxPoints.right = 0;
  

    while (MapPtr->DirectXEnumWallList(Wall))
    {
        if (Wall.Point3.x == -1)
        {
            // it is a wall
            RenderAddWall(Wall.Start,Wall.End);
            LAUtils.FormRect(MaxPoints,Wall.Start,Wall.End);
        }
        else
        {
            // it is a roof
            RenderAddRoof(Wall.Start,Wall.End,Wall.Point3);
        }

    }

    RenderAddFloor(MaxPoints);

    RenderCreateWallVertexBuffer();
}


/************************************************************************
* FunctionResetView()
*
* PURPOSE
* To Reset the view
* USAGE
* By the main view window on a reset command
*************************************************************************/
void SDirectX::ResetView()
{

    TheCamera.At = D3DXVECTOR3(6,0,6);
    TheCamera.Eye = D3DXVECTOR3(6,6,0);
    TheCamera.Orientation = D3DXVECTOR3(0,1,0); // y is up (most of the time)
    
    TheCamera.MoveDown = false;
    TheCamera.MoveLeft = false;
    TheCamera.MoveRight = false;
    TheCamera.MoveUp = false;   

    TheCamera.XAngle =  -45;
    TheCamera.YAngle = 0;

    TheCamera.CameraMode = Chase;
    TheCamera.ChaseDistance = 0.05f;
    TheCamera.ChaseAngleX = 45;
    TheCamera.ChaseAngleY = 0;
    TheCamera.ChaseOffset.x = 0;
    TheCamera.ChaseOffset.y = 0;
    
    RenderControl.ZoomRatio = 1.0f;

}

/************************************************************************
* void AdjustCameraPosition()
*
* PURPOSE
* To increment the camera position if a camera movement key is depressed
* USAGE
* Currently in the rendering loop
*************************************************************************/
void SDirectX::AdjustCameraPosition()
{
    float Movement = 0.1f;

    // fixed angle
    if (TheCamera.CameraMode == FixedAngle)
    {

        if (TheCamera.MoveDown)
        {
            TheCamera.At.z -= Movement*RenderControl.ZoomRatio;
        }
        else if (TheCamera.MoveUp)
        {
            TheCamera.At.z += Movement*RenderControl.ZoomRatio;
        }
        else if (TheCamera.MoveRight)
        {
            TheCamera.At.x += Movement*RenderControl.ZoomRatio;
        }
        else if (TheCamera.MoveLeft)
        {
            TheCamera.At.x -= Movement*RenderControl.ZoomRatio;
        }    

        TheCamera.Eye = TheCamera.At;

        TheCamera.Eye.z += 8*RenderControl.ZoomRatio;
        TheCamera.Eye.y += 10*RenderControl.ZoomRatio;
    }
    // uses the mouse to change angle and standard 3D button (w-a-s-d) to move forward and stafe
    // Because of some assumption with the 3D coordinate camera it isn't perfect
    else if (TheCamera.CameraMode == Game3D)
    {
        Movement = 0.001f;
		float Fast = 0.01f;
		float Medium = 0.006f;
		BOOL AnyKey = false;
		int NeedFast = 40;
		int NeedMedium = 20;

        //This mode is based on the camera being moved and the "AT" vector being generated by
        //the camera angles
		float dx,dy,dz;

        if (TheCamera.MoveDown || TheCamera.MoveUp)
        {
            // first calculate the vectors from the current angle           
           float Sign;		   

           if (TheCamera.MoveUp)
		   {
               Sign = 1;
			   if (TheCamera.LastKey == KUp)
			   {
				   TheCamera.KeyAccleration++;
			   }
			   else
			   {
				   TheCamera.KeyAccleration = 0;
			   }
			   AnyKey = true;
			   TheCamera.LastKey = KUp;
		   }
           else if(TheCamera.MoveDown)
		   {
               Sign = -1;
			   if (TheCamera.LastKey == KDown)
			   {
				   TheCamera.KeyAccleration++;
			   }				   
			   else
			   {
				   TheCamera.KeyAccleration = 0;
			   }

			   AnyKey = true;
			   TheCamera.LastKey = KDown;
		   }
		   if (TheCamera.KeyAccleration > NeedFast)
		   {
			   Movement = Fast;
		   }
		   else if (TheCamera.KeyAccleration > NeedMedium)
		   {
			   Movement = Medium;
		   }

           AdjustCameraPosition(dx,dy,dz,TheCamera.XAngle,TheCamera.YAngle,Movement);


            // now move the camera position accordingly.
           TheCamera.Eye.x += Sign*dx;
           TheCamera.Eye.y += Sign*dy;
           TheCamera.Eye.z += Sign*dz;    
        }
        else if (TheCamera.MoveRight)
        {
		   if (TheCamera.LastKey == KRight)
		   {
			   TheCamera.KeyAccleration++;
		   }
		   else
		   {
			   TheCamera.KeyAccleration = 0;
		   }

		   if (TheCamera.KeyAccleration > NeedFast)
		   {
			   Movement = Fast;
		   }
		   else if (TheCamera.KeyAccleration > NeedMedium)
		   {
			   Movement = Medium;
		   }
		   AnyKey = true;

		   AdjustCameraPosition(dx,dy,dz,TheCamera.XAngle,TheCamera.YAngle+90,Movement);

		   TheCamera.Eye.x += dx;
           TheCamera.Eye.z += dz;   
		   
		   
		   TheCamera.LastKey = KRight;
        }
        else if (TheCamera.MoveLeft)
        {			
		   if (TheCamera.LastKey == KLeft)
		   {
			   TheCamera.KeyAccleration++;
		   }
		   else
		   {
			   TheCamera.KeyAccleration = 0;
		   }
		   if (TheCamera.KeyAccleration > NeedFast)
		   {
			   Movement = Fast;
		   }
		   else if (TheCamera.KeyAccleration > NeedMedium)
		   {
			   Movement = Medium;
		   }
		   AnyKey = true;
		   TheCamera.LastKey = KLeft;

		   AdjustCameraPosition(dx,dy,dz,TheCamera.XAngle,TheCamera.YAngle-90,Movement); 

		   TheCamera.Eye.x += dx;  
           TheCamera.Eye.z += dz; 

        } 
		
		if (!AnyKey)
		{
			TheCamera.LastKey = KNone;
			TheCamera.KeyAccleration = 0;
		}

        // now create the "AT" vector by using the camera angle and any disance
        AdjustCameraPosition(dx,dy,dz,TheCamera.XAngle,TheCamera.YAngle,5);
       
        TheCamera.At.x = TheCamera.Eye.x + dx;
        TheCamera.At.y = TheCamera.Eye.y + dy;
        TheCamera.At.z = TheCamera.Eye.z + dz;
    }
    // chase model.  Follow the robot from behind, at the robots angle
    // Chase angle and chase distance are adjustable
    else if (TheCamera.CameraMode == Chase)
    {
        // first find out the offsets if any

        float ZOffset = cosf((TheCamera.ModelAngle - 90)*(float)PI/180)*TheCamera.ChaseOffset.y;
        float XOffset = sinf((TheCamera.ModelAngle - 90)*(float)PI/180)*TheCamera.ChaseOffset.y;

        TheCamera.At.y = 0;
        TheCamera.At.x = TheCamera.ModelCenter.x/1000.0f + XOffset; // scaling
        TheCamera.At.z = TheCamera.ModelCenter.y/1000.0f + ZOffset; // scaling

        TheCamera.YAngle = TheCamera.ModelAngle - 90 + TheCamera.ChaseAngleY;

        if (TheCamera.MoveDown)
        {
            TheCamera.ChaseDistance += 0.02f;
        }
        else if (TheCamera.MoveUp)
        {
            TheCamera.ChaseDistance -= 0.02f;
            if (TheCamera.ChaseDistance < 0.05f)
                TheCamera.ChaseDistance = 0.05f;
        }
        
        else if (TheCamera.MoveRight)
        {
            TheCamera.ChaseOffset.y += 0.02f;
        }
        else if (TheCamera.MoveLeft)
        {
            TheCamera.ChaseOffset.y -= 0.02f;
        }    

        float dx,dy,dz;

        AdjustCameraPosition(dx,dy,dz,TheCamera.ChaseAngleX,TheCamera.YAngle,TheCamera.ChaseDistance);

        if (LAUtils.Abs(dx) < .0001 && LAUtils.Abs(dz) < .0001)
            dz = .0001f*LAUtils.Sgn(dz);

        TheCamera.Eye.x = TheCamera.At.x + dx;
        // couldn't figure out how to make y uniform to x and z because 
        TheCamera.Eye.y = TheCamera.At.y + dy;// + TheCamera.ChaseAngleX*TheCamera.ChaseDistance ;
        TheCamera.Eye.z = TheCamera.At.z + dz;
    }

}

/************************************************************************
* void OnChar(UNIT Char)
*
* PURPOSE
* If Camera movement is enabled this selects a camera movement, if the key is valid
* USAGE
* By the Onchar in the main view window
*************************************************************************/
void SDirectX::OnChar(UINT Char)
{
    TheCamera.MoveDown = false;
    TheCamera.MoveLeft = false;
    TheCamera.MoveRight = false;
    TheCamera.MoveUp = false;

    if (isalpha(Char))
    {
        if ('A' == Char)
            TheCamera.MoveLeft = true;
        else if ('D' == Char)
            TheCamera.MoveRight = true;
        else if ('W' == Char)
            TheCamera.MoveUp = true;
        else if ('S' == Char)
            TheCamera.MoveDown = true;
    }

}

/************************************************************************
* void OnResetChar()
*
* PURPOSE
* If Camera movement, this resets the characters
* USAGE
* By the OnKeyUp in the main view window
*************************************************************************/
void SDirectX::OnResetChar()
{
    TheCamera.MoveDown = false;
    TheCamera.MoveLeft = false;
    TheCamera.MoveRight = false;
    TheCamera.MoveUp = false;
}

/************************************************************************
* void RenderAddFloor(FRect Floor)
*
* PURPOSE
* This function could be called by anyone during a directX rendering loop.  It creates
* a floor to all of the lines created
* USAGE
* Probably quadtree
* OUTPUT
* Internally adds some vertices to the vertex buffer.
*************************************************************************/
void SDirectX::RenderAddFloor(FRect FloorRect)
{
    WallStructPtr NewPtr;

    NewPtr = new WALLSTRUCT;

    NewPtr->Start.x = FloorRect.left;
    NewPtr->Start.y = FloorRect.top;
    NewPtr->End.x = FloorRect.right;
    NewPtr->End.y = FloorRect.bottom;
    NewPtr->Type = Floor;
    NewPtr->Next = WallStruct.WallPtr;
    WallStruct.WallPtr = NewPtr;


}

/************************************************************************
* Function RCZoom(CPoint Point)
* 
* PURPOSE
* To Zoom in/out the view, when the mouse moves
* USAGE
* Called by the window class
*************************************************************************/
void SDirectX::RCZoom(CPoint Point)
{
    float ZoomFactor = (float)(1-(float)((Point.y-RenderControl.PrevZoomedPoint.y))*ZOOMPIXELPERCENT);

    RenderControl.PrevZoomedPoint = Point;

    RenderControl.ZoomRatio *=ZoomFactor;

}



/************************************************************************
* Function RCSetZoomPoint(CPoint Point
* 
* PURPOSE
* To set the center point at which to zoom
* USAGE
* Called by the window class
*************************************************************************/
void SDirectX::RCSetZoomPoint(CPoint Point)
{
    RenderControl.PrevZoomedPoint = Point;


}

/************************************************************************
* void RenderAddRoof(FPoint Point1, FPoint Point2, FPoint Point3)
*
* PURPOSE
* This function could be called by anyone during a directX rendering loop.  It creates
* a roof for a wall segment
* USAGE
* Probably quadtree
* OUTPUT
* Internally adds some vertices to the vertex buffer.
*************************************************************************/
void SDirectX::RenderAddRoof(FPoint Point1, FPoint Point2, FPoint Point3)
{
    WallStructPtr NewPtr;

    NewPtr = new WALLSTRUCT;

    NewPtr->Start = Point1;
    NewPtr->End = Point2;
    NewPtr->Extra = Point3;
    NewPtr->Type = Roof;
    NewPtr->Next = WallStruct.RoofPtr;
    WallStruct.RoofPtr = NewPtr;
    
    WallStruct.RoofBufferCount++;

}

/************************************************************************
* void RenderFormWall(VERTEX *pVertex, FPoint Start, FPoint End)
*
* PURPOSE
* Loads a vertex buffer with roof coordinates
*************************************************************************/
void SDirectX::RenderFormRoof(VERTEX *pVertex, FPoint Start, FPoint End, FPoint Extra)
{
    float height = DEFAULTHEIGHT;

	DWORD Color1 = 0xff00ffff;


	pVertex[0].position.x = Start.x;
	pVertex[0].position.y = height;
	pVertex[0].position.z = Start.y;
	pVertex[0].color = Color1;
	pVertex[0].tu = 0.0f;
	pVertex[0].tv = 0.0f;


	pVertex[1].position.x = End.x;
	pVertex[1].position.y = height;
	pVertex[1].position.z = End.y;
	pVertex[1].color = Color1;
	pVertex[1].tu = 1.0f;
	pVertex[1].tv = 1.0f;

	pVertex[2].position.x = Extra.x;
	pVertex[2].position.y = height;
	pVertex[2].position.z = Extra.y;
	pVertex[2].color = Color1;
	pVertex[2].tu = 0.0f;
	pVertex[2].tv = 1.0f;

}

/************************************************************************
* void RenderModel()
*
* PURPOSE
* Renders the model
*************************************************************************/
void SDirectX::RenderModel()
{
     if (Robot.Valid)
     {
		 	
		 float NScaling = 0.0001f;
		 float IScaling = 1000*NScaling;

		 // offsets because the model isn't precisly centered in its bounds
		 float ZOffset = -Robot.ModelOffCenterZ*cosf((TheCamera.ModelAngle+90)*PI/180.0f);
		 float XOffset = -Robot.ModelOffCenterZ*sinf((TheCamera.ModelAngle+90)*PI/180.0f);;
		 

        D3DXMATRIX matrixWorld,Rotation1,Rotation2,Rotation3,Translation,Scaling;

        D3DXMatrixIdentity(&Rotation1);  
		D3DXMatrixIdentity(&Rotation2); 
		D3DXMatrixIdentity(&Rotation3); 
        D3DXMatrixIdentity(&Translation);		
        D3DXMatrixScaling(&Scaling,NScaling,NScaling,NScaling);
        

	 
        D3DXMatrixRotationY(&Rotation1,(TheCamera.ModelAngle-90)*(float)PI/180);
	
			D3DXMatrixRotationX(&Rotation2, 90.0f*(float)PI/180);
			D3DXMatrixRotationZ(&Rotation3,180.0f*(float)PI/180);
        D3DXMatrixTranslation(&Translation,(TheCamera.ModelCenter.x+XOffset)/IScaling,1.0f,(TheCamera.ModelCenter.y+ZOffset)/IScaling); 
        matrixWorld =Rotation2*Rotation3* Rotation1*Translation*Scaling;

     
	    m_pd3dDevice->SetTransform( D3DTS_WORLD, &matrixWorld );

	    m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
	    m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );


       // Set up the textures
       /* m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );*/

        Robot.Mesh->Render(m_pd3dDevice,TRUE,TRUE);
		
		if (Robot.SonarValid)
		{
			 float NScaling = 0.0001f;
			 float IScaling = 1000*NScaling;

			 // offsets because the model isn't precisly centered in its bounds
			 float ZOffset = -Robot.ModelOffCenterZ*cosf((TheCamera.ModelAngle+90)*PI/180.0f);
			 float XOffset = -Robot.ModelOffCenterZ*sinf((TheCamera.ModelAngle+90)*PI/180.0f);;
			 

			D3DXMATRIX matrixWorld,Rotation1,Rotation2,Rotation3,Translation,Scaling;


			D3DXMatrixIdentity(&Rotation1); 
			D3DXMatrixIdentity(&Rotation2); 
			D3DXMatrixIdentity(&Rotation3);  

			// rotate it 90 because of offset in 3DS max model
			D3DXMatrixRotationZ(&Rotation2, 90.0f*(float)PI/180);

			D3DXMatrixIdentity(&Translation);
			D3DXMatrixScaling(&Scaling,NScaling,NScaling,NScaling);
        		
			// rotate it so the sonar matches up with its real angle
			float SonarAngle = SModel->TheModel.Sensors.SonarSensor.DirectXGetAngle();
			D3DXMatrixRotationY(&Rotation3,(SonarAngle-180)*(float)PI/180.0f);

			D3DXMatrixTranslation(&Translation,(TheCamera.ModelCenter.x+XOffset)/IScaling,120.0f,(TheCamera.ModelCenter.y+ZOffset)/IScaling); 
			matrixWorld =Rotation2*Rotation3* Rotation1*Translation*Scaling;

			m_pd3dDevice->SetTransform( D3DTS_WORLD, &matrixWorld );

			Robot.Sonar->Render(m_pd3dDevice,TRUE,TRUE);


		}

		// now render the treads
		D3DVECTOR CenterPoint;
		// figure out the center point of the right tread
		float TreadRadius = 9.0f;

			    m_pd3dDevice->SetTexture(0,m_pTreadTexture);	// No Texture


		m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE  );
		m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE                    );
		m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_CURRENT                   );
		m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );

/*m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
    m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );*/


	D3DMATERIAL8 mtrl;
    D3DUtil_InitMaterial( mtrl, 10.0f, 10.100f, 10.01f );
    m_pd3dDevice->SetMaterial( &mtrl );

		CenterPoint.x = TheCamera.ModelCenter.x + XOffset + TreadRadius*sinf((TheCamera.ModelAngle)*PI/180.0f);
		CenterPoint.z = TheCamera.ModelCenter.y+ ZOffset + TreadRadius*cosf((TheCamera.ModelAngle)*PI/180.0f);
		CenterPoint.y = 1.00f; // just a bit above ground level
		Robot.RightTread.Update(SModel->TheModel.Sensors.ShaftEncoders.GetRightDelta(),CenterPoint,TheCamera.ModelAngle);	
		Robot.RightTread.Render();

		
		CenterPoint.x = TheCamera.ModelCenter.x  + XOffset + TreadRadius*sinf((TheCamera.ModelAngle+180)*PI/180.0f);
		CenterPoint.z = TheCamera.ModelCenter.y + ZOffset + TreadRadius*cosf((TheCamera.ModelAngle+180)*PI/180.0f);
		CenterPoint.y = 1.00f; // just a bit above ground level
		Robot.LeftTread.Update(SModel->TheModel.Sensors.ShaftEncoders.GetLeftDelta(),CenterPoint,TheCamera.ModelAngle);
		Robot.LeftTread.Render();

		m_pd3dDevice->SetTexture(0,NULL/*m_pFloorTexture*/);

	
     }
    
}

/************************************************************************
* void OnMouseMove(CPoint Point)
*
* PURPOSE
* This function changes the camera angle in Game3D camera mode
* USAGE
* By the onmove of the main window
*************************************************************************/
void SDirectX::OnMouseMove(CPoint Point)
{
    float AngleRatio = 0.3f;
    if ((TheCamera.CameraMode == Game3D) || (TheCamera.CameraMode == Chase))
    {
        if (OldMousePoint.x == -1)
        {
        }
        else
        {
            float DeltaX = (float)(OldMousePoint.x - Point.x);
            float DeltaY = (float)(OldMousePoint.y - Point.y);
            if (TheCamera.CameraMode == Game3D)
            {                
                TheCamera.XAngle += DeltaY*AngleRatio;
                TheCamera.YAngle += DeltaX*AngleRatio;
            }
            else if (TheCamera.CameraMode == Chase)
            {
                TheCamera.ChaseAngleX += AngleRatio*DeltaY;
                if (TheCamera.ChaseAngleX < 0.05f)
                    TheCamera.ChaseAngleX = 0.05f;
                if (TheCamera.ChaseAngleX > 89.5f)
                {
                    TheCamera.ChaseAngleX = 89.5f;

                }

                TheCamera.ChaseAngleY += AngleRatio*DeltaX;

            }
			TheCamera.XAngle = LAUtils.Mod360(TheCamera.XAngle);
			TheCamera.YAngle = LAUtils.Mod360(TheCamera.YAngle);
        }
        OldMousePoint = Point;
    }
}

/************************************************************************
* void OnResetMouse()
*
* PURPOSE
* Resets the mouse for the 3D game camera mode
* USAGE
* By the main window
*************************************************************************/
void SDirectX::OnResetMouse()
{
    OldMousePoint.x = -1;

}

/************************************************************************
* void AdjustCameraPosition(float &dx, float &dy, float &dz, float AngleX, float AngleY, float Radius)
*
* PURPOSE
* Main helper function for AdjustCameraPosition.  It uses 3D spheric to sove dx,dy and dz based on 2 angles
* and a radius.  Doesn't work perfectly.  Some assumptions and shortcuts were made.  Couldn't fully
* Solve the problem due to the TAN function only being accurate in 2 Quadrants out of the 4.
* USAGE
* by AdjustCameraPosition()
*************************************************************************/
void SDirectX::AdjustCameraPosition(float &dx, float &dy, float &dz, float AngleX, float AngleY, float Radius)
{

    // might as well mod them
    AngleX = LAUtils.Mod360(AngleX);
    AngleY = LAUtils.Mod360(AngleY);
  

    float TanX = (float)tan(AngleX*PI/180);
    float TanY = (float)tan(AngleY*PI/180);
  
        
    if (TanY == 0)
    {
        // go back to a 2D model
        dx = 0;
        dy = Radius*(float)sin(AngleX*PI/180);
        dz = Radius*(float)cos(AngleX*PI/180);       

    }        
    else if (TanX == 0)
    {
        // go back to a 2D model
        dy = 0;
        dx = Radius*(float)sin(AngleY*PI/180);
        dz = Radius*(float)cos(AngleY*PI/180);
    }
    else
    {
        // new way
        // first resolve the y and z coordinate and then backtrack to resolve the x coordinate
        dy = Radius*(float)sin(AngleX*PI/180);
        dz = Radius*(float)cos(AngleX*PI/180);    
        
        // o.k resolve dz and dx using the old dx as the radius
        Radius = dz;
        dx = Radius*(float)sin(AngleY*PI/180);
        dz = Radius*(float)cos(AngleY*PI/180);
    }




        // old way
      /*  // 3D model, sphere
        dz = Radius/(float)sqrt(1+TanX*TanX+TanY*TanY);   
        
        dx = dz*TanY;

        dy = TanX*dz;

        // O.K to compinsate for the TAN only being right in two quadrants AngleY is used to 
        // rectify it.  However AngleX may also have an error, so it is later rectified with a
        // flip all (including camera up.
        // this was done with a lot of trial and error so don't ask!
        if (AngleY < 90)
        {
            if (dz < 0)
                dz = -dz;
            if (dx < 0)
                dx = -dx;    
        }
        else if (AngleY < 180)
        {
            if (dz > 0)
                dz = -dz;
            if (dx < 0)
                dx = -dx; 
        }
        else if (AngleY < 270)
        {
            if (dz > 0)
                dz = -dz; 
            if (dx > 0)
                dx = -dx; 
        }
        else if (AngleY < 270)
        {
            if (dz < 0)
                dz = -dz;
            if (dx > 0)
                dx = -dx; 
        }

         if (AngleX >= 90 && AngleX <= 270)
         {

                dx = -dx;
                dy = -dy;
                dz = -dz;

                if (TheCamera.Orientation.y > 0)
                    TheCamera.Orientation.y = -TheCamera.Orientation.y; 

         }
         else
         {
             if (TheCamera.Orientation.y < 0)
                    TheCamera.Orientation.y = -TheCamera.Orientation.y; 
         }

    }*/

}

/************************************************************************
* SetCameraType(int CameraType)
*
* PURPOSE
* Sets the Camera Type
* USAGE
* By main window (rending options dialog actually)
*************************************************************************/
void SDirectX::SetCameraType(int CameraType)
{
    TheCamera.CameraMode = (CAMERAMODE)CameraType;

}

/************************************************************************
* LoadModels()
*
* PURPOSE
* Loads in the meshes from a file
* USAGE
* On the intialization
*************************************************************************/
void SDirectX::LoadModels()
{

    if (Robot.Mesh != NULL)
        SAFE_DELETE(Robot.Mesh);
	if (Robot.Sonar != NULL)
        SAFE_DELETE(Robot.Sonar);

    Robot.Mesh = new CD3DMesh;
	Robot.Sonar = new CD3DMesh;

    if (Robot.Mesh->Create(m_pd3dDevice,ROBOTFILE) != S_OK)
    {
        Robot.Valid = false;
        AfxMessageBox("Warning, Could not load model");
    }
    else
    {
        Robot.Valid = true;
        // Set up the geometry objects
        Robot.Mesh->RestoreDeviceObjects( m_pd3dDevice );
    }

    if (Robot.Sonar->Create(m_pd3dDevice,SONARFILE) != S_OK)
    {
        Robot.SonarValid = false;
        AfxMessageBox("Warning, Could not load sonar model");
    }
    else
    {
        Robot.SonarValid = true;
        // Set up the geometry objects
        Robot.Sonar->RestoreDeviceObjects( m_pd3dDevice );
    }




}

/************************************************************************
* void RenderSensors()
*
* PURPOSE
* Renders the sensors effect
* USAGE
* Called inside of render() during a rendering loop
*************************************************************************/
void SDirectX::RenderSensors()
{
    VERTEX* pVertices; // pointer for traversal of VB

    SModel->DirectXSetupEnum(TheCamera.ModelCenter);

    SGenericModel::DFPoint TwoPoints;

    int VertexCount = 0;

    // lock the buffer
    if( FAILED( g_pModelVB->Lock(0, 0, (BYTE**)&pVertices, 0 ) ) )
    {
        return;
    }

    VERTEX* pCurrVertex = pVertices;

    // form vertex buffer
    while (SModel->DirectXEnum(TwoPoints))
    {
        RenderFormBumper(pCurrVertex,TwoPoints.Point1,TwoPoints.Point2);
        pCurrVertex = pCurrVertex + 6;
        VertexCount += 2;
    } 

    SModel->TheModel.Sensors.IRSensors.DirectXRender(pCurrVertex,TheCamera.ModelCenter,VertexCount);
    SModel->TheModel.Sensors.SonarSensor.DirectXRender(pCurrVertex,TheCamera.ModelCenter,VertexCount);
    

	g_pModelVB->Unlock();

    // enable alpha blending
    m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE , TRUE);

    // setup the alphablending parameters
    m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA  );
    m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA   ); 

        
    if (VertexCount > 0)
    {
    // now render them
        m_pd3dDevice->SetStreamSource( 0, g_pModelVB, sizeof(VERTEX) );
	    m_pd3dDevice->SetVertexShader( VERTEX_TYPE );

	    m_pd3dDevice->SetTexture(0,NULL);	// No Texture

    //	m_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);	// Wireframe for dubugging
        m_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
	    
	    m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);	// Enable Z buffering

	    // Draw the Triangles
	    m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, VertexCount);

    }

    // disable alpha blending
    m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE , FALSE);

}

/************************************************************************
* void RCToggleAltTexture()
*
* PURPOSE
* Toggle the different texture types
*************************************************************************/
void SDirectX::RCToggleAltTexture()
{
	if (EnableAltTexture)
		EnableAltTexture = false;
	else
		EnableAltTexture = true;

}
