
#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9tex.h>
#include <iostream>
#include "UIcomponent.h"
#include "3Dheader.h"

//DirectX declarations

LPDIRECT3D9 pD3D;
LPDIRECT3DDEVICE9 pd3dDevice;

using namespace std;

int xRes = 600;
int yRes = 480;

RECT backgroundRect;
IDirect3DSurface9* backgroundSurface;
UIcomponent* firstComponent;

IDirect3DSurface9* LoadSurfaceFromFile(std::string FileName);

enum renderstage {unindexed, indexed};

static renderstage r = indexed;

void setMatrices()
{
    //--------------transformation code----------------//
    D3DXMATRIX objectM, translationM, rotationM, projectionM, lookAtM, finalM;

	HRESULT hr;

	D3DXMatrixIdentity(&objectM);
	D3DXMatrixRotationY(&rotationM, D3DX_PI/4);
	D3DXMatrixMultiply(&finalM, &objectM, &rotationM);

	D3DXMatrixPerspectiveFovLH(&projectionM,D3DX_PI/4,(float)xRes/yRes, 1, 100);

	D3DXVECTOR3 camera;
	camera.x = -10;
	camera.y = 10;
	camera.z = 0;
	D3DXVECTOR3 cameraTarget;
	cameraTarget.x = 0;
	cameraTarget.y = 0;
	cameraTarget.z = 0;
	D3DXVECTOR3 cameraUp;
	cameraUp.x = 0;
	cameraUp.y = 1;
	cameraUp.z = 0;
	D3DXMatrixLookAtLH(&lookAtM,&camera,&cameraTarget, &cameraUp);

	hr = pd3dDevice->SetTransform(D3DTS_WORLD, &finalM);
	hr = pd3dDevice->SetTransform(D3DTS_PROJECTION, &projectionM);
	hr = pd3dDevice->SetTransform(D3DTS_VIEW, &lookAtM);
	
	D3DXMATRIX textureM;
	D3DXMatrixMultiply(&textureM,&finalM, &projectionM);
	D3DXMatrixMultiply(&textureM,&textureM, &lookAtM);

	pd3dDevice->SetTransform(D3DTS_TEXTURE0, &textureM);

	D3DVIEWPORT9 view_port;

	view_port.X=0;
	view_port.Y=0;
	view_port.Width=xRes;
	view_port.Height=yRes;
	view_port.MinZ=0.0f;
	view_port.MaxZ=1.0f;

	//setLight(pd3dDevice);

	//pd3dDevice->SetViewport(&view_port);
}

void Render3D()
{
	pd3dDevice->BeginScene();

	setMatrices();

	pd3dDevice->SetTexture(0, tex);
	//pd3dDevice->SetRenderState(D3DRS_WRAP0, D3DWRAPCOORD_0);
	pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
	pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

	pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);

	//pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

    // select which vertex format we are using
    pd3dDevice->SetFVF(CUSTOMFVF);

    // select the vertex buffer to display
    pd3dDevice->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));

	pd3dDevice->SetIndices(i_buffer);

    // copy the vertex buffer to the back buffer
	pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
									0,
									0,
									8,
									0,
									12);
	pd3dDevice->EndScene();
}

void Render3D_unindexed()
{
	pd3dDevice->BeginScene();
    // select which vertex format we are using
    pd3dDevice->SetFVF(CUSTOMFVF);

    // select the vertex buffer to display
    pd3dDevice->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));

    // copy the vertex buffer to the back buffer
    pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
	pd3dDevice->EndScene();
}

void RenderUI()
{
	if(firstComponent == NULL)
	{
		return;
	}
	UIcomponent* ui = firstComponent;
	renderUI:
	ui->render();
	if(ui->next != NULL)
	{
		ui = ui->next;
		goto renderUI;
	}

}

void initGlobalVars()
{
	backgroundRect.top = 0;
	backgroundRect.bottom = yRes;
	backgroundRect.left = 0;
	backgroundRect.right = xRes;
}

void initGlobalVars(int x, int y)
{
	xRes = x;
	yRes = y;
	initGlobalVars();
}

void addUIcomponent(UIcomponent *e)
{
	e->next = firstComponent;
	firstComponent = e;
}

void initPostD3D()
{
	backgroundSurface = LoadSurfaceFromFile("C:\\MicrosoftDirectX.JPG");
	firstComponent = new UIcomponent("C:\\directx-logo.jpg",xRes-100,0,100,100,pd3dDevice);
	firstComponent->assignFunction(exit);
	addUIcomponent(new UIcomponent("C:\\MicrosoftDirectX.JPG",0,0,xRes,yRes,pd3dDevice));

	switch(r)
	{
	case indexed:
		{
			init_graphics(pd3dDevice);    // call the function to initialize the triangle
			break;
		}
	case unindexed:
		{
			init_graphics_unindexed(pd3dDevice);
			break;
		}
	}
}

void render(void)
{
	static IDirect3DSurface9* backBuffer;
	pd3dDevice->GetBackBuffer(0,NULL, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
	if(NULL == pd3dDevice)
	{
		return;
	}
	pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);

	RenderUI();
	switch(r)
	{
	case indexed:
		{
			Render3D();
			break;
		}
	case unindexed:
		{
			Render3D_unindexed();
			break;
		}
	}

	pd3dDevice->Present(NULL,NULL, NULL, NULL);
}

void cleanUp(void)
{
    v_buffer->Release();    // close and release the vertex buffer
	if(pd3dDevice != NULL)
	{
		pd3dDevice->Release();
	}
	if(pD3D != NULL)
	{
		pD3D->Release();
	}
}

bool initDirect3D()
{
	pD3D = NULL;
	pd3dDevice = NULL;

	//Create DirectX object
	if(NULL == (pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		return false;
	}

	HWND hWnd;

	getHandle:
	hWnd = GetActiveWindow();
	if(GetParent(hWnd) != NULL)
		goto getHandle;

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.Windowed = true;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferHeight = yRes;
	d3dpp.BackBufferWidth = xRes;
	d3dpp.hDeviceWindow = hWnd;

	if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice)))
	{
		return false;
	}
	return true;
}

IDirect3DSurface9* LoadSurfaceFromFile(std::string FileName)
{
	HRESULT hResult;
	IDirect3DSurface9* surface = NULL;
	D3DXIMAGE_INFO imageInfo;
	wstring ws(FileName.begin(), FileName.end());//we need a Long Pointer to Constant Wide STRing
	LPCWSTR str = ws.c_str();//so we get a pointer to a proper string to begin with
	hResult = D3DXGetImageInfoFromFile(str, &imageInfo);
	if(FAILED(hResult))
	{
		//return NULL;
		imageInfo.Height = 824;
		imageInfo.Width = 2000;
		imageInfo.Depth = 32;
	}
	hResult = pd3dDevice->CreateOffscreenPlainSurface(imageInfo.Width, 
													  imageInfo.Height,
													  D3DFMT_X8R8G8B8,
													  D3DPOOL_DEFAULT,
													  &surface,
													  NULL);
	if(FAILED(hResult))
	{
		return NULL;
	}

	hResult = D3DXLoadSurfaceFromFile(surface, NULL, NULL, str, NULL, D3DX_DEFAULT, 0, NULL);

	if(FAILED(hResult))
	{
		return NULL;
	}

	return surface;
}

void handleMouse(int x, int y)
{
	UIrespond(firstComponent, x, y);
}