// DlgCreateMegatexture.cpp : implementation file
//

#include "stdafx.h"
#include "Megatron.h"
#include "DlgCreateMegatexture.h"

#include <elementrenderer\elementrendererheaders.hpp>
#include "Proxies\ProxyHeaders.hpp"
#include "ElementProxies\ElementProxies.hpp"
#include <GameOS\ToolOS.hpp>

//#include <proxies\ArrangeMegaTextures.hpp>

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

/////////////////////////////////////////////////////////////////////////////
// CDlgCreateMegatexture dialog


CDlgCreateMegatexture::CDlgCreateMegatexture(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgCreateMegatexture::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDlgCreateMegatexture)
	//}}AFX_DATA_INIT
	m_pList = NULL;
	m_pCell = NULL;
	m_pImage = NULL;
	m_pNoteFile = NULL;
}

CDlgCreateMegatexture::~CDlgCreateMegatexture()
{
	if (m_pCell)
		delete m_pCell;
	if (m_pImage)
		delete m_pImage;
}

void CDlgCreateMegatexture::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgCreateMegatexture)
	DDX_Control(pDX, IDC_NAME, m_wndName);
	DDX_Control(pDX, IDC_MEGAPREVIEW, m_wndMegaPreview);
	DDX_Control(pDX, IDC_LIST, m_wndList);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CDlgCreateMegatexture, CDialog)
	//{{AFX_MSG_MAP(CDlgCreateMegatexture)
	ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
	ON_WM_DRAWITEM()
	ON_BN_CLICKED(IDC_RADIO1, OnRadio1)
	ON_BN_CLICKED(IDC_RADIO2, OnRadio2)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDlgCreateMegatexture message handlers

BOOL CDlgCreateMegatexture::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	CWnd *pWnd = GetDlgItem(IDC_RADIO2);
	((CButton *)pWnd)->SetCheck(true);
	OnRadio2();

	CPtrList *poslist = NULL;
	if (m_pList)
	{
		POSITION pos = m_pList->GetHeadPosition();
		if (pos)
		{
			poslist = (CPtrList *)m_pList->GetNext(pos);
		}
		while (pos)
		{
			bool bsel = false;
			if (POSITION pos1 = poslist->Find((LPVOID)pos))
			{
				poslist->RemoveAt(pos1);
				bsel = true;
			}

			Stuff::Page *page = (Stuff::Page *)m_pList->GetNext(pos);
			Check_Object(page);
			int index = m_wndList.AddString(page->GetName());
			m_wndList.SetItemData(index,(DWORD)page);
			if (bsel)
			{
				m_wndList.SetSel(index,true);
			}
		}
	}
	OnSelchangeList();
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

static CDWordArray arrVerts;

CCell::CCell()
{
	bSplit = false;
	for (int x=0;x<4;x++)
		m_arrChildren[x] = NULL;
	m_image = NULL;
	state = 0;
}

CCell::~CCell()
{
	for (int x=0;x<4;x++)
		if (m_arrChildren[x])
			delete m_arrChildren[x];
}

CPoint CCell::GetPoint1()
{
	DWORD dw = arrVerts[V1];
	CPoint pt(LOWORD(dw),HIWORD(dw));
	return pt;
}

int CCell::AddVert(int x,int y)
{
	DWORD dw = MAKELONG(x,y);
	return arrVerts.Add(dw);
}

int CCell::GetXDim()
{
	DWORD dw1 = arrVerts[V1];
	WORD x1 = LOWORD(dw1);

	DWORD dw2 = arrVerts[V2];
	WORD x2 = LOWORD(dw2);
	return (x2-x1);
}

int CCell::GetYDim()
{
	DWORD dw1 = arrVerts[V1];
	WORD y1 = HIWORD(dw1);

	DWORD dw2 = arrVerts[V2];
	WORD y2 = HIWORD(dw2);
	return (y2-y1);
}

int CCell::GetV1()
{
	return V1;
}

int CCell::GetV2()
{
	return V2;
}

int CCell::SetVerts(int a,int b)
{
	V1 = a;
	V2 = b;
	return 1;
}

int CCell::CreateCell(int xSize,int ySize)
{
	V1 = AddVert(0,0);
	V2 = AddVert(xSize,ySize);
	state = 0;	// Empty
	return 1;
}

CCell *CCell::FillCell(Image *image)
{
	if (2==state)
		return NULL;
	int xSize = image->GetWidth();
	int ySize = image->GetHeight();

	int xdim = GetXDim();
	int ydim = GetYDim();

	if ((xSize==xdim)&&(ySize==ydim)&&(0==state))
	{
		// use this cell, fill it up totally
		m_image = image;
		name = image->GetFileName();
		state = 2;
		return this;
	}
	else
	{
		if ((xSize<=xdim) && (ySize<=ydim))
		{
			SplitCell(xSize,ySize);
			BYTE flags = 0;
			for (int x=0;x<4;x++)
			{
				CCell *cell = m_arrChildren[x]->FillCell(image);
				flags |= (2==m_arrChildren[x]->state) << x;
				if (cell)
				{
					if (15==flags)
						state = 2;
					else 
						state = 1;
					return cell;
				}
			}

		}
		else
		{
			// Cannot fill this cell with something this big, unless I union with neighbors
			return NULL;
		}
	}
	return NULL;
}

int CCell::SplitCell(int xSize,int ySize)
{
	if (!bSplit)
	{
		CPoint pt1 = GetPoint1();
		int xdim = GetXDim();
		int ydim = GetYDim();

		int topleft = GetV1();
		int bottomright = GetV2();
		int middle = AddVert(pt1.x+xSize,pt1.y+ySize);
		int middletop = AddVert(pt1.x+xSize,pt1.y);
		int middleleft = AddVert(pt1.x,pt1.y+ySize);
		int middlebottom = AddVert(pt1.x+xSize,pt1.y+ydim);
		int middleright = AddVert(pt1.x+xdim,pt1.y+ySize);

		CCell *cell = m_arrChildren[0] = new CCell;
		cell->SetVerts(topleft,middle);

		cell = m_arrChildren[1] = new CCell;
		cell->SetVerts(middletop,middleright);

		cell = m_arrChildren[2] = new CCell;
		cell->SetVerts(middleleft,middlebottom);

		cell = m_arrChildren[3] = new CCell;
		cell->SetVerts(middle,bottomright);

		bSplit = true;
	}
	return 4;
}

int BuildMegaTexture(CCell *pCell,Image *pImage)
{
	if (pCell)
	{
		if (pCell->m_image)
		{
			CPoint pt = pCell->GetPoint1();
			pImage->Blt(*(pCell->m_image),pt.x,pt.y);
		}
		for (int x=0;x<4;x++)
			BuildMegaTexture(pCell->m_arrChildren[x],pImage);
	}
	return 1;
}

CCell *ArrangeTextures(Stuff::NotationFile *pMega_file,CString mega_name,int xSize,int ySize,CMapStringToPtr *pMapImages,Image *mega_image)
{
	Stuff::Page *mega_page = pMega_file->AddPage(mega_name);
	CString str;
	str.Format("%d %d",xSize,ySize);
	mega_page->AppendEntry("PageSize",str);

	CCell *pCell = new CCell;
	pCell->CreateCell(xSize,ySize);

	POSITION pos = pMapImages->GetStartPosition();
	while (pos)
	{
		CString imagename;
		LPVOID lpvoid;
		pMapImages->GetNextAssoc(pos,imagename,lpvoid);
		Image *pImage = (Image *)lpvoid;
		
		CCell *cell = pCell->FillCell(pImage);
		if (NULL == cell)
		{
			CString str;
			str.Format("Could not fit texture %s",imagename);
			MessageBox(NULL,str,"Fill Cell",MB_OK);
		}
	}

	BuildMegaTexture(pCell,mega_image);
	return pCell;
}

void CDlgCreateMegatexture::OnSelchangeList() 
{
	CString mega_name = "MegaTexture";

	int iCount = m_wndList.GetSelCount();
	int *items = new int[iCount];
	m_wndList.GetSelItems(iCount,items);

	CMapStringToPtr mapImages;
	for (int x=0;x<iCount;x++)
	{
		Stuff::Page *page = (Stuff::Page *)m_wndList.GetItemData(items[x]);

		CString imagename = page->GetName();
		const char *entry;
		if (page->GetEntry("Alias",&entry))
		{
			imagename = entry;
		}

		CString path = "content\\textures\\"+imagename;

		Image *image = new Image;

		CString fullname = path+".tga";
		if (gos_DoesFileExist(fullname))
		{
			image->Load((char *)(LPCTSTR)fullname);
		}
		else
		{
			fullname = path+".png";
			if (gos_DoesFileExist(fullname))
			{
				image->Load((char *)(LPCTSTR)fullname);
			}
		}
					if(image->GetBpp()==32)
						image->MaskTo(RGBMask(0x00ff0000,0x0000ff00,0x000000ff,0xff000000));
					else
						image->MaskTo(RGBMask(0x00ff0000,0x0000ff00,0x000000ff));


		mapImages[imagename] = image;


/*		m_BackBuffer.DeleteObject();
		m_wndMegaPreview.Invalidate();

		CDC  memDC,*hfDC;
		hfDC=GetDC();

		BOOL bres;
		bres=m_BackBuffer.CreateCompatibleBitmap(hfDC,image.GetWidth(),image.GetHeight());
		Verify(bres);

		memDC.CreateCompatibleDC(hfDC);
		memDC.SelectObject(&m_BackBuffer);

		BITMAPINFOHEADER bhd;
		BITMAPINFO       binf;
		bhd.biSize=sizeof(BITMAPINFOHEADER);
		bhd.biWidth=image.GetWidth(); bhd.biHeight=-image.GetHeight();
		bhd.biPlanes=1;
		bhd.biBitCount=image.GetBpp();
		bhd.biCompression=BI_RGB;
		bhd.biSizeImage=0;
		bhd.biClrImportant=0;
		binf.bmiHeader=bhd;

		BYTE *imgdat=(BYTE *)(image.Lock());

		SetDIBitsToDevice(memDC,0,0,image.GetWidth(),
		image.GetHeight(),0,0,0,image.GetWidth(),imgdat,
		&binf,DIB_RGB_COLORS);  

		image.UnLock();

		memDC.DeleteDC();
		ReleaseDC(hfDC);*/
	}
	delete items;

	
	Stuff::NotationFile mega_file;
	if (m_pCell)
		delete m_pCell;
	if (m_pImage)
		delete m_pImage;

	m_pImage = new Image;
	m_pImage->CreateSolid(pagesize,pagesize,ImgRGBColor(0xff,0xff,0xff,0xff),ITYPE_RGB,32);
	
	m_pCell = ArrangeTextures(&mega_file,mega_name,pagesize,pagesize,&mapImages,m_pImage);


	POSITION pos = mapImages.GetStartPosition();
	while (pos)
	{
		CString imagename;
		LPVOID lpvoid;
		mapImages.GetNextAssoc(pos,imagename,lpvoid);
		Image *pImage = (Image *)lpvoid;
		
		delete pImage;
	}
	mapImages.RemoveAll();





	//mega_page->AppendEntry("Texture",imagename);


		// Create the scene stuff
/*	ElementRenderer::GroupElement *root = new ElementRenderer::GroupElement;
	Check_Object(root);

	ElementProxies::ElementSceneProxy *element_scene =
		ElementProxies::ElementSceneProxy::MakeProxy(
			root,
			"content\\textures\\"
		);
	Check_Object(element_scene);

	ElementProxies::MLRStatePoolProxy *state_library = Cast_Object(ElementProxies::MLRStatePoolProxy *,element_scene->GetStateLibrary());
	Check_Object(state_library);

	Proxies::TextureLibrary *texture_library = state_library->GetTextureLibrary();
	Check_Object(texture_library);


	// do the arranging

	Proxies::ArrangeMegatexturesProcess arrange_process(&mega_file);
	texture_library->ArrangeMegatextures(&arrange_process);
/*
	Proxies::BuildMegatexturesProcess build_process(&mega_file);
	texture_library->BuildMegatextures(&build_process);
*/
	// Recycle the texture library
	//
	//delete texture_library;
	//delete state_library;

/*	element_scene->Destroy();

	if (ElementProxies::MLRTexturePoolProxy::Instance)
	{
		ElementProxies::MLRTexturePoolProxy::Instance->CloseLibrary(true);
	}
	//delete root;


	/*CString targa_name = "content\\textures\\";
	targa_name+=mega_name+".tga";

	Proxies::TextureProxy *texture_proxy = texture_library->UseTextureProxy(mega_name);
	texture_proxy->SaveAsTarga(targa_name);

*/
	{
	/*	CString path = "content\\textures\\"+mega_name;

		Image image;

		CString fullname = path+".tga";
		if (gos_DoesFileExist(fullname))
		{
			image.Load((char *)(LPCTSTR)fullname);
		}
		/*else
		{
			fullname = path+".png";
			if (gos_DoesFileExist(fullname))
			{
				image.Load((char *)(LPCTSTR)fullname);
			}
		}*/

		m_BackBuffer.DeleteObject();
		m_wndMegaPreview.Invalidate();

		CDC  memDC,*hfDC;
		hfDC=GetDC();

		BOOL bres;
		bres=m_BackBuffer.CreateCompatibleBitmap(hfDC,m_pImage->GetWidth(),m_pImage->GetHeight());
		Verify(bres);

		memDC.CreateCompatibleDC(hfDC);
		memDC.SelectObject(&m_BackBuffer);

		BITMAPINFOHEADER bhd;
		BITMAPINFO       binf;
		bhd.biSize=sizeof(BITMAPINFOHEADER);
		bhd.biWidth=m_pImage->GetWidth(); bhd.biHeight=-m_pImage->GetHeight();
		bhd.biPlanes=1;
		bhd.biBitCount=m_pImage->GetBpp();
		bhd.biCompression=BI_RGB;
		bhd.biSizeImage=0;
		bhd.biClrImportant=0;
		binf.bmiHeader=bhd;

		BYTE *imgdat=(BYTE *)(m_pImage->Lock());

		SetDIBitsToDevice(memDC,0,0,m_pImage->GetWidth(),
		m_pImage->GetHeight(),0,0,0,m_pImage->GetWidth(),imgdat,
		&binf,DIB_RGB_COLORS);  

		m_pImage->UnLock();

		memDC.DeleteDC();
		ReleaseDC(hfDC);
	}

	mega_file.IgnoreChanges();
}

void CDlgCreateMegatexture::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	switch (lpDrawItemStruct->CtlID)
	{
	case IDC_MEGAPREVIEW:
		{
			CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

			HBITMAP hBitmap = m_BackBuffer;
			if (hBitmap)
			{
				CDC  memDC;
				int res;
				
				BITMAP bmp;
				res=m_BackBuffer.GetBitmap(&bmp);
				Verify(res);
				
				BOOL bres;
				bres=memDC.CreateCompatibleDC(pDC);
				Verify(bres);
				memDC.SelectObject(&m_BackBuffer);
				CRect hfrct;
				GetClientRect(&hfrct);
				//pDC->SetStretchBltMode(COLORONCOLOR);
				bres=pDC->BitBlt(0,0,hfrct.Width(),hfrct.Height(),&memDC,0,0,SRCCOPY);
				Verify(bres);
				memDC.DeleteDC();
			}
			return;
		}
	}
	CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

int ConstructPage(CCell *pCell,Stuff::Page *page)
{
	if (NULL == pCell)
		return 0;
	if (pCell->m_image)
		// Acutally m_image is already deleted by now so I can't use it
	{
		char name[MAX_PATH];
		_splitpath(pCell->name,NULL,NULL,name,NULL);
		CString str;
		CPoint pt = pCell->GetPoint1();
		str.Format("%d %d",pt.x,pt.y);
		page->AppendEntry(name,str);
	}
	int count = 1;
	for (int x=0;x<4;x++)
	{
		count += ConstructPage(pCell->m_arrChildren[x],page);
	}
	return count;
}

void CDlgCreateMegatexture::OnOK() 
{
	CString str;
	m_wndName.GetWindowText(str);
	if (str.GetLength()==0)
	{
		MessageBox("Must give new Megatexture a name");
		return;
	}
	if (NULL == m_pImage)
	{
		MessageBox("Must select at least one image to create Megatexture");
		return;
	}

	Stuff::Page *page = m_pNoteFile->AddPage(str);
	CString str1;
	str1.Format("%d %d",pagesize,pagesize);
	page->AppendEntry("PageSize",str1);
	ConstructPage(m_pCell,page);

	str = "content\\textures\\"+str+".tga";
	m_pImage->SaveTga((char *)(LPCTSTR)str);

	CDialog::OnOK();
}

void CDlgCreateMegatexture::OnRadio1() 
{
	pagesize = 256;	
	OnSelchangeList();
}

void CDlgCreateMegatexture::OnRadio2() 
{
	pagesize = 512;	
	OnSelchangeList();
}
