// MorphingDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Morphing.h"
#include "MorphingDlg.h"

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

#define MODE_MESH	1
#define MODE_FIELD	2
#define MAX_LINE	15

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMorphingDlg dialog

CMorphingDlg::CMorphingDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMorphingDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMorphingDlg)
	m_strStep = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMorphingDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMorphingDlg)
	DDX_Control(pDX, IDC_PROGRESS, m_ctlProgress);
	DDX_Text(pDX, IDC_STEP, m_strStep);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMorphingDlg, CDialog)
	//{{AFX_MSG_MAP(CMorphingDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_CONVERT, OnConvert)
	ON_WM_DESTROY()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_BN_CLICKED(IDC_OPEN, OnOpen)
	ON_BN_CLICKED(IDC_RADIO_MESH, OnRadioMesh)
	ON_BN_CLICKED(IDC_CANCEL, OnCancel)
	ON_BN_CLICKED(IDC_RADIO_FIELD, OnRadioField)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMorphingDlg message handlers

BOOL CMorphingDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here

	// init variable
	m_pMeshWarp = new CMeshWarp;
	m_pSrcMeshPoint = NULL;
	m_pDestMeshPoint = NULL;
	m_pSrcFieldLine = NULL;
	m_pDestFieldLine = NULL;
	m_pSrcIMG = new CIMG;
	m_pDestIMG = new CIMG;
	m_pSrcBackDC = new CDC;
	m_pDestBackDC = new CDC;

	m_nNumLine = 0;
	m_nSelected = -1;
	m_bStartPoint = true;
	m_bOpened = false;
	m_nMorphStep = 0;

	CButton* pButton;
	pButton = (CButton*)GetDlgItem(IDC_RADIO_MESH);
	pButton->SetCheck(1);

	m_bMouseClick = false;
	m_nMode = MODE_MESH;

	// Init start position
	m_srcPoint.x = 10;
	m_srcPoint.y = 40;
	
	SetWindowSize(0, 0);

	m_strStep.Format("%d", m_nMorphStep);
	UpdateData(false);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMorphingDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMorphingDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CPaintDC dc(this);
		if (m_bOpened)
		{
			int widthBMP = m_pSrcIMG->Width();
			int heightBMP = m_pSrcIMG->Height();

			// Blit source image
			dc.BitBlt(m_srcPoint.x, m_srcPoint.y, widthBMP + 2, heightBMP + 2, m_pSrcBackDC, 0, 0, SRCCOPY);
			dc.BitBlt(m_destPoint.x, m_destPoint.y, widthBMP + 2, heightBMP + 2, m_pDestBackDC, 0, 0, SRCCOPY);

		}
		
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMorphingDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CMorphingDlg::OnOpen() 
{
	char szFilters[] = "Jpeg Files (*.jpeg;*.jpg)|*.jpeg;*.jpg|";
	CFileDialog dlg(true, NULL, NULL, OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilters, this);

	if (dlg.DoModal() == IDOK)
	{
		// Init
		m_nMorphStep = 0;

		// Load bitmap
		m_pSrcIMG = new CIMG;
		if (!m_pSrcIMG->OpenIMG(dlg.GetPathName()))
		{
			delete m_pSrcIMG;
			m_pSrcIMG = NULL;
			MessageBox("file open error!!");
			return;
		}

		int width = m_pSrcIMG->Width();
		int height = m_pSrcIMG->Height();

		if (dlg.DoModal() == IDOK)
		{			
			// Load bitmap
			m_pDestIMG = new CIMG;
			if (!m_pDestIMG->OpenIMG(dlg.GetPathName())) {
				delete m_pDestIMG;
				m_pDestIMG = NULL;
				MessageBox("file open error!!");
				return;
			}

			// Get bitmap size
			if (width != m_pDestIMG->Width() || height != m_pDestIMG->Height()) {
				delete m_pSrcIMG;
				m_pSrcIMG = NULL;
				delete m_pDestIMG;
				m_pDestIMG = NULL;
				MessageBox("you should open same size image!!");
				return;
			}

			// Init start position
			m_destPoint.x = 40 + width;
			m_destPoint.y = m_srcPoint.y;

			// Set window size
			SetWindowSize(width, height);

			CPaintDC dc(this);
			if (m_pSrcBackDC != NULL)
				delete m_pSrcBackDC;
			if (m_pDestBackDC != NULL)
				delete m_pDestBackDC;

			m_pSrcBackDC = new CDC;
			m_pDestBackDC = new CDC;

			// create back DC for Double buffering
			m_pSrcBackDC->CreateCompatibleDC(&dc);	
			m_pDestBackDC->CreateCompatibleDC(&dc);	

			CBitmap srcBitmap, destBitmap;
			srcBitmap.CreateCompatibleBitmap(&dc, width + 2, height + 2);
			destBitmap.CreateCompatibleBitmap(&dc, width + 2, height + 2);

			m_pSrcBackDC->SelectObject(&srcBitmap);
			m_pDestBackDC->SelectObject(&destBitmap);

			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);

			InvalidateRect(NULL, TRUE);
			m_bOpened = TRUE;
		}
	}
}

void CMorphingDlg::OnConvert() 
{
	if (m_bOpened == FALSE)
	{
		MessageBox("open image file!!");
		return;
	}

	if(m_nMode == MODE_MESH)
	{
		switch(m_nMorphStep)
		{
			case 0:
			{
				m_nMeshWidth = 5 + 2;
				m_nMeshHeight = 5 + 2;

				AllocateMeshPoint();

				int widthBMP = m_pSrcIMG->Width();
				int heightBMP = m_pSrcIMG->Height();
				float interN = (float)widthBMP / (float)((float)m_nMeshWidth - 1.0f);
				float interH = (float)heightBMP / (float)((float)m_nMeshHeight - 1.0f);

				for (int i = 0; i < m_nMeshWidth; i++)
				{
					for (int j = 0; j < m_nMeshHeight; j++)
					{
						int c = j * m_nMeshWidth + i;
						if (i < m_nMeshWidth - 1)
							m_pSrcMeshPoint[c].x = (int)(interN * (float)i);
						else
							m_pSrcMeshPoint[c].x = widthBMP - 1;
						if (j < m_nMeshHeight - 1)
							m_pSrcMeshPoint[c].y = (int)(interH * (float)j);
						else
							m_pSrcMeshPoint[c].y = heightBMP - 1;
					}
				}

				m_nMorphStep = 1;		// Next Process

				m_mouseMesh.x = m_mouseMesh.y = -1;

				DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

				InvalidateRect(NULL, FALSE);

				break;
			}
			case 1:
			{
				for (int i = 0; i < m_nMeshWidth; i++)
				{
					for (int j = 0; j < m_nMeshHeight; j++)
					{
						int c = j * m_nMeshWidth + i;
						if (i < m_nMeshWidth - 1)
							m_pDestMeshPoint[c].x = m_pSrcMeshPoint[c].x;
						else
							m_pDestMeshPoint[c].x = m_pSrcMeshPoint[c].x;
						if (j < m_nMeshHeight - 1)
							m_pDestMeshPoint[c].y = m_pSrcMeshPoint[c].y;
						else
							m_pDestMeshPoint[c].y = m_pSrcMeshPoint[c].y;
					}
				}

				m_nMorphStep = 2;		// Next Process
				m_mouseMesh.x = m_mouseMesh.y = -1;

				DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

				InvalidateRect(NULL, FALSE);
				
				break;
			} 
			case 2:
			{	// apply morphing
				m_nMorphStep = 0;
				CIMG dest, result;
				// Copy source
				dest.Create(m_pSrcIMG->Width(), m_pSrcIMG->Height(), 24);
				result.Create(m_pSrcIMG->Width(), m_pSrcIMG->Height(), 24);

				int frame, duration;
				BOOL bMF = FALSE;
				frame = 30;			// default 0.1 frame / sec
				duration = 1;		// default 1 second
				
				// Mesh Warping
				float u = 0.0f;
				float diff = (1.0f * duration) / (float)frame;
				CIMGList list;
				int count = 0;

				m_ctlProgress.SetRange(0, frame);

				while (u <= 1.0f)
				{
					m_pMeshWarp->Morphing(m_pSrcIMG, 
										  m_pDestIMG, 
										  &dest, 
										  m_pSrcMeshPoint, 
										  m_pDestMeshPoint, 
										  m_nMeshWidth, 
										  m_nMeshHeight, 
										  u);
					list.InsertNodeTail(&dest);
					/*CString s;
					s.Format("%d.bmp", (int)(u * frame));
					dest.SaveIMG(s);*/
					u += diff;
					m_ctlProgress.SetPos((int)(u * frame));
				}

				Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
				Draw(m_pDestBackDC, m_pDestIMG, 1, 1);

				CMorphPlayDlg morphPlayDlg;
				morphPlayDlg.SetVariable(&list, frame, duration);
				
				morphPlayDlg.DoModal();

				InvalidateRect(NULL, FALSE);
				DeallocateMeshPoint();
				m_ctlProgress.SetPos(0);

				break;
			}
		}
	}
	else if(m_nMode == MODE_FIELD)
	{
		switch(m_nMorphStep)
		{
			case 0:
			{
				AllocateFieldLine();

				m_nMorphStep = 1;		// Next Process

				InvalidateRect(NULL, FALSE);

				break;
			}
			case 1:
			{
				if(!m_nNumLine)
				{
					MessageBox("draw a control line!!");
					return;
				}

				for (int i = 0; i < m_nNumLine; i++)
				{
					m_pDestFieldLine[i].start.x = m_pSrcFieldLine[i].start.x;
					m_pDestFieldLine[i].start.y = m_pSrcFieldLine[i].start.y;
					m_pDestFieldLine[i].end.x = m_pSrcFieldLine[i].end.x;
					m_pDestFieldLine[i].end.y = m_pSrcFieldLine[i].end.y;
				}

				m_nMorphStep = 2;		// Next Process
				
				DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

				InvalidateRect(NULL, FALSE);
				
				break;
			} 
			case 2:
			{	// apply morphing
				m_nMorphStep = 0;
				CIMG dest, result;
				// Copy source
				dest.Create(m_pSrcIMG->Width(), m_pSrcIMG->Height(), 24);
				result.Create(m_pSrcIMG->Width(), m_pSrcIMG->Height(), 24);

				int frame, duration;
				BOOL bMF = FALSE;
				frame = 30;			// default 0.1 frame / sec
				duration = 1;		// default 1 second
				
				// Mesh Warping
				float u = 0.0f;
				float diff = (1.0f * duration) / (float)frame;
				CIMGList list;
				int count = 0;

				m_ctlProgress.SetRange(0, frame);

				while (u <= 1.0f)
				{
					m_pFieldWarp->Morphing(m_pSrcIMG, 
										  m_pDestIMG, 
										  &dest, 
										  m_pSrcFieldLine, 
										  m_pDestFieldLine, 
										  m_nNumLine,
										  u);
					list.InsertNodeTail(&dest);
					/*CString s;
					s.Format("%d.bmp", (int)(u * frame));
					dest.SaveIMG(s);*/
					u += diff;
					m_ctlProgress.SetPos((int)(u * frame));
				}

				Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
				Draw(m_pDestBackDC, m_pDestIMG, 1, 1);

				CMorphPlayDlg morphPlayDlg;
				morphPlayDlg.SetVariable(&list, frame, duration);
				
				morphPlayDlg.DoModal();

				InvalidateRect(NULL, FALSE);
				DeallocateMeshPoint();
				m_nNumLine = 0;
				m_nSelected = -1;
				m_ctlProgress.SetPos(0);
	
				break;
			}
		}
	}
	
	m_strStep.Format("%d", m_nMorphStep);
	UpdateData(false);
}

void CMorphingDlg::OnDestroy() 
{
	CDialog::OnDestroy();
	
	if (m_pSrcBackDC != NULL) delete m_pSrcBackDC;
	if (m_pDestBackDC != NULL) delete m_pDestBackDC;
	
	if (m_pMeshWarp != NULL) delete m_pMeshWarp;	

	if (m_pSrcIMG != NULL) delete m_pSrcIMG;
	if (m_pDestIMG != NULL) delete m_pDestIMG;
}

void CMorphingDlg::AllocateMeshPoint()
{
	// init mesh point
	m_pSrcMeshPoint = (MESHPOINT *)malloc(sizeof(MESHPOINT) * m_nMeshHeight * m_nMeshWidth);
	m_pDestMeshPoint = (MESHPOINT *)malloc(sizeof(MESHPOINT) * m_nMeshHeight * m_nMeshWidth);
}

void CMorphingDlg::AllocateFieldLine()
{
	// init mesh point
	m_pSrcFieldLine = (FIELDLINE *)malloc(sizeof(FIELDLINE) * MAX_LINE);
	m_pDestFieldLine = (FIELDLINE *)malloc(sizeof(FIELDLINE) * MAX_LINE);
}

void CMorphingDlg::DeallocateMeshPoint()
{
	delete [] m_pSrcMeshPoint;
	delete [] m_pDestMeshPoint;
}

void CMorphingDlg::DeallocateFieldLine()
{
	delete [] m_pSrcFieldLine;
	delete [] m_pDestFieldLine;
}

void CMorphingDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	if(m_nMode == MODE_MESH)
	{
		if (m_nMorphStep == 1 && (m_mouseMesh.x != -1 && m_mouseMesh.y != -1))
		{
			// setup coordinate
			m_pSrcMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].x = point.x - m_srcPoint.x;
			m_pSrcMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].y = point.y - m_srcPoint.y;

			// update
			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
		else if (m_nMorphStep == 2 && (m_mouseMesh.x != -1 && m_mouseMesh.y != -1))
		{
			// setup coordinate
			m_pDestMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].x = point.x - m_destPoint.x;
			m_pDestMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].y = point.y - m_destPoint.y;

			// update
			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
	}
	else if(m_nMode == MODE_FIELD && m_bMouseClick)
	{
		if (m_nMorphStep == 1 && m_nNumLine <= MAX_LINE)
		{
			// setup coordinate
			m_pSrcFieldLine[m_nNumLine - 1].end.x = point.x - m_srcPoint.x;
			m_pSrcFieldLine[m_nNumLine - 1].end.y = point.y - m_srcPoint.y;

			// update
			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
		else if (m_nMorphStep == 2 && m_nSelected > -1)
		{
			// update
			if(m_bStartPoint)
			{
				m_pDestFieldLine[m_nSelected].start.x = point.x - m_destPoint.x;
				m_pDestFieldLine[m_nSelected].start.y = point.y - m_destPoint.y;
			}
			else
			{
				m_pDestFieldLine[m_nSelected].end.x = point.x - m_destPoint.x;
				m_pDestFieldLine[m_nSelected].end.y = point.y - m_destPoint.y;
			}

			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CMorphingDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if(m_nMode == MODE_MESH)
	{
		if (m_nMorphStep == 1 && m_mouseMesh.x == -1 && m_mouseMesh.y == -1)
		{
			// search mesh point
			for (int i = 1; i < m_nMeshWidth - 1; i++)
			{
				for (int j = 1; j < m_nMeshHeight - 1; j++)
				{
					int c = j * m_nMeshWidth + i;
					if (point.x <= m_srcPoint.x + m_pSrcMeshPoint[c].x + 2 && point.x >= m_srcPoint.x + m_pSrcMeshPoint[c].x - 2 &&
						point.y <= m_srcPoint.y + m_pSrcMeshPoint[c].y + 2 && point.y >= m_srcPoint.y + m_pSrcMeshPoint[c].y - 2) {
						m_mouseMesh.x = i;
						m_mouseMesh.y = j;
						break;
					}
				}
			}
		}
		else if (m_nMorphStep == 2 && m_mouseMesh.x == -1 && m_mouseMesh.y == -1)
		{
			// search mesh point
			for (int i = 1; i < m_nMeshWidth - 1; i++)
			{
				for (int j = 1; j < m_nMeshHeight - 1; j++) {
					int c = j * m_nMeshWidth + i;
					if (point.x <= m_destPoint.x + m_pDestMeshPoint[c].x + 2 && point.x >= m_destPoint.x + m_pDestMeshPoint[c].x - 2 &&
						point.y <= m_destPoint.y + m_pDestMeshPoint[c].y + 2 && point.y >= m_destPoint.y + m_pDestMeshPoint[c].y - 2) {
						m_mouseMesh.x = i;
						m_mouseMesh.y = j;
						break;
					}
				}
			}
		}
	}
	else if(m_nMode == MODE_FIELD && !m_bMouseClick)
	{
		if (m_nMorphStep == 1 && point.x > m_srcPoint.x && point.y > m_srcPoint.y
			&& point.x < m_srcPoint.x + m_pSrcIMG->Width() && point.y < m_srcPoint.y + m_pSrcIMG->Height())
		{
			m_bMouseClick = true;
			m_nNumLine++;
			if(m_nNumLine <= MAX_LINE)
			{
				m_pSrcFieldLine[m_nNumLine - 1].start.x = point.x - m_srcPoint.x;
				m_pSrcFieldLine[m_nNumLine - 1].start.y = point.y - m_srcPoint.y;

				Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
				Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
				DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

				InvalidateRect(NULL, FALSE);
			}
			else
				MessageBox("라인은 15개까지 그릴수 있습니다.");
		}
		else if (m_nMorphStep == 2 && point.x > m_destPoint.x && point.y > m_destPoint.y
			&& point.x < m_destPoint.x + m_pSrcIMG->Width() && point.y < m_destPoint.y + m_pSrcIMG->Height())
		{
			m_bMouseClick = false;
			m_bStartPoint = false;
			m_nSelected = -1;

			for(int i = 0; i < m_nNumLine; i++)
			{
				if(point.x <= m_destPoint.x + m_pDestFieldLine[i].start.x + 2 && point.x >= m_destPoint.x + m_pDestFieldLine[i].start.x - 2 &&
						point.y <= m_destPoint.y + m_pDestFieldLine[i].start.y + 2 && point.y >= m_destPoint.y + m_pDestFieldLine[i].start.y - 2)
				{
					m_bMouseClick = true;
					m_bStartPoint = true;
					m_nSelected = i;
					break;
				}
				if(point.x <= m_destPoint.x + m_pDestFieldLine[i].end.x + 2 && point.x >= m_destPoint.x + m_pDestFieldLine[i].end.x - 2 &&
						point.y <= m_destPoint.y + m_pDestFieldLine[i].end.y + 2 && point.y >= m_destPoint.y + m_pDestFieldLine[i].end.y - 2)
				{
					m_bMouseClick = true;
					m_bStartPoint = false;
					m_nSelected = i;
					break;
				}
			}
		}
	}
	
	CDialog::OnLButtonDown(nFlags, point);
}

void CMorphingDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
	m_bMouseClick = false;
	int resultX, resultY;
	int nWidth = m_pSrcIMG->Width();
	int nHeight = m_pSrcIMG->Height();

	if(m_nMode == MODE_MESH)
	{
		if (m_nMorphStep == 1 && m_mouseMesh.x != -1 && m_mouseMesh.y != -1) {
			if (point.x - m_srcPoint.x < 0)
				resultX = 0;
			else if (point.x - m_srcPoint.x > nWidth - 1)
				resultX = nWidth - 1;
			else 
				resultX = point.x - m_srcPoint.x;

			if (point.y - m_srcPoint.y < 0)
				resultY = 0;
			else if (point.y - m_srcPoint.y > nHeight - 1)
				resultY = nHeight - 1;
			else 
				resultY = point.y - m_srcPoint.y;

			// setup coordinate
			m_pSrcMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].x = resultX;
			m_pSrcMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].y = resultY;
			// init
			m_mouseMesh.x = m_mouseMesh.y = -1;
			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		} else if (m_nMorphStep == 2 && m_mouseMesh.x != -1 && m_mouseMesh.y != -1) {
			if (point.x - m_destPoint.x < 0)
				resultX = 0;
			else if (point.x - m_destPoint.x > nWidth - 1)
				resultX = nWidth - 1;
			else 
				resultX = point.x - m_destPoint.x;

			if (point.y - m_destPoint.y < 0)
				resultY = 0;
			else if (point.y - m_destPoint.y > nHeight - 1)
				resultY = nHeight - 1;
			else 
				resultY = point.y - m_destPoint.y;
			
			// setup coordinate
			m_pDestMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].x = resultX;
			m_pDestMeshPoint[m_mouseMesh.x + m_mouseMesh.y * m_nMeshWidth].y = resultY;
			// init
			m_mouseMesh.x = m_mouseMesh.y = -1;
			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawMeshMorphPoint(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
	}
	else if(m_nMode == MODE_FIELD && m_bMouseClick)
	{
		if (m_nMorphStep == 1 && m_nNumLine <= MAX_LINE)
		{
			m_pSrcFieldLine[m_nNumLine - 1].end.x = point.x - m_srcPoint.x;
			m_pSrcFieldLine[m_nNumLine - 1].end.y = point.y - m_srcPoint.y;

			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}
		else if (m_nMorphStep == 2 && m_nSelected > -1)
		{
			// update
			if(m_bStartPoint)
			{
				m_pDestFieldLine[m_nSelected].start.x = point.x - m_destPoint.x;
				m_pDestFieldLine[m_nSelected].start.y = point.y - m_destPoint.y;
			}
			else
			{
				m_pDestFieldLine[m_nSelected].end.x = point.x - m_destPoint.x;
				m_pDestFieldLine[m_nSelected].end.y = point.y - m_destPoint.y;
			}

			Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
			Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
			DrawFieldMorphLine(m_pSrcBackDC, m_pDestBackDC);

			InvalidateRect(NULL, FALSE);
		}

	}

	CDialog::OnLButtonUp(nFlags, point);
}

void CMorphingDlg::Draw(CDC *dc, CIMG *src, int x, int y)
{
	int nWidth = src->Width();
	int nHeight = src->Height();
	src->Draw(dc->m_hDC, x, y, nWidth, nHeight, 0, 0, nWidth, nHeight);

	// Draw edge
	CPen blackPen, *pOldPen;
	blackPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	pOldPen = dc->SelectObject(&blackPen);
	dc->MoveTo(x - 1, y - 1);
	dc->LineTo(x + nWidth, y - 1);
	dc->LineTo(x + nWidth, y + nHeight);
	dc->LineTo(x - 1, y + nHeight);
	dc->LineTo(x - 1, y - 1);
	dc->SelectObject(pOldPen);
}

void CMorphingDlg::SetWindowSize(int width, int height)
{
	int wndWidth, wndHeight;
	RECT rect;

	// compute window size
	wndWidth = width * 2 + m_srcPoint.x * 3;
	wndWidth = (wndWidth > DEFAULT_WIDTH) ? wndWidth : DEFAULT_WIDTH;
	wndHeight = m_srcPoint.y + height + 40;
	wndHeight = (wndHeight > DEFAULT_HEIGHT) ? wndHeight : DEFAULT_HEIGHT;

	// get old size
	this->GetWindowRect(&rect);
	
	// change size
	this->SetWindowPos(&this->wndTop, rect.left, rect.top, wndWidth, wndHeight, SWP_SHOWWINDOW);
}

void CMorphingDlg::DrawMeshMorphPoint(CDC *pSrcDC, CDC *pDestDC)
{
	CPen *pOldPen, redPen, greenPen;
		
	redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
	greenPen.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

	switch(m_nMorphStep) 
	{
		case 2: // 두번째 메쉬 break가 없어서 첫번째 메쉬도 같이 그린다.
		{
			for (int i = 1; i < m_nMeshWidth; i++)
			{
				for(int j = 1; j < m_nMeshHeight; j++)
				{
					int c = j * m_nMeshWidth + i;
					int c1 = (j - 1) * m_nMeshWidth + i;

					pOldPen = pDestDC->SelectObject(&redPen);
					if (i < m_nMeshWidth - 1)
					{
						pDestDC->MoveTo(1 + m_pDestMeshPoint[c1].x, 1 + m_pDestMeshPoint[c1].y);
						pDestDC->LineTo(1 + m_pDestMeshPoint[c].x, 1 + m_pDestMeshPoint[c].y);
					}
					else
						pDestDC->MoveTo(1 + m_pDestMeshPoint[c].x, 1 + m_pDestMeshPoint[c].y);

					if (j < m_nMeshHeight - 1)
						pDestDC->LineTo(1 + m_pDestMeshPoint[c - 1].x, 1 + m_pDestMeshPoint[c - 1].y);
				}
			}

			for (i = 1; i < m_nMeshWidth - 1; i++)
			{
				for(int j = 1; j < m_nMeshHeight - 1; j++)
				{
					int c = j * m_nMeshWidth + i;
					
					pDestDC->Ellipse(1 + m_pDestMeshPoint[c].x - 3, 1 + m_pDestMeshPoint[c].y - 3, 
									 1 + m_pDestMeshPoint[c].x - 3 + 6, 1 + m_pDestMeshPoint[c].y - 3 + 6);
				}
			}
		}
		case 1: // 첫번째 메쉬
		{
			for (int i = 1; i < m_nMeshWidth; i++)
			{
				for(int j = 1; j < m_nMeshHeight; j++)
				{
					int c = j * m_nMeshWidth + i;
					int c1 = (j - 1) * m_nMeshWidth + i;
					
					pOldPen = pSrcDC->SelectObject(&greenPen);
					if (i < m_nMeshWidth - 1)
					{
						pSrcDC->MoveTo(1 + m_pSrcMeshPoint[c1].x, 1 + m_pSrcMeshPoint[c1].y);
						pSrcDC->LineTo(1 + m_pSrcMeshPoint[c].x, 1 + m_pSrcMeshPoint[c].y);
					}
					else
						pSrcDC->MoveTo(1 + m_pSrcMeshPoint[c].x, 1 + m_pSrcMeshPoint[c].y);

					if (j < m_nMeshHeight - 1)
						pSrcDC->LineTo(1 + m_pSrcMeshPoint[c - 1].x, 1 + m_pSrcMeshPoint[c - 1].y);
				}
			}

			for (i = 1; i < m_nMeshWidth - 1; i++)
			{
				for(int j = 1; j < m_nMeshHeight - 1; j++)
				{
					int c = j * m_nMeshWidth + i;
					
					pSrcDC->Ellipse(1 + m_pSrcMeshPoint[c].x - 3, 1 + m_pSrcMeshPoint[c].y - 3, 
									 1 + m_pSrcMeshPoint[c].x - 3 + 6, 1 + m_pSrcMeshPoint[c].y - 3 + 6);
				}
			}

			break;
		}
	}
	pSrcDC->SelectObject(pOldPen);
	pDestDC->SelectObject(pOldPen);
}

void CMorphingDlg::DrawFieldMorphLine(CDC *pSrcDC, CDC *pDestDC)
{
	CPen *pOldPen, redPen, greenPen;
		
	redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
	greenPen.CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

	switch(m_nMorphStep) 
	{
		case 2: // 두번째 라인 break가 없어서 첫번째 라인도 같이 그린다.
		{
			pOldPen = pDestDC->SelectObject(&redPen);
			for (int i = 0; i < m_nNumLine; i++)
			{
				pDestDC->MoveTo(1 + m_pDestFieldLine[i].start.x, 1 + m_pDestFieldLine[i].start.y);
				pDestDC->LineTo(1 + m_pDestFieldLine[i].end.x, 1 + m_pDestFieldLine[i].end.y);
			}

			for (i = 0; i < m_nNumLine; i++)
			{
				pDestDC->Ellipse(1 + m_pDestFieldLine[i].start.x - 3, 1 + m_pDestFieldLine[i].start.y - 3, 
						1 + m_pDestFieldLine[i].start.x - 3 + 6, 1 + m_pDestFieldLine[i].start.y - 3 + 6);
				pDestDC->Ellipse(1 + m_pDestFieldLine[i].end.x - 3, 1 + m_pDestFieldLine[i].end.y - 3, 
						1 + m_pDestFieldLine[i].end.x - 3 + 6, 1 + m_pDestFieldLine[i].end.y - 3 + 6);
			}
		}
		case 1: // 첫번째 라인
		{
			pOldPen = pSrcDC->SelectObject(&greenPen);
			for (int i = 0; i < m_nNumLine; i++)
			{
				pSrcDC->MoveTo(1 + m_pSrcFieldLine[i].start.x, 1 + m_pSrcFieldLine[i].start.y);
				pSrcDC->LineTo(1 + m_pSrcFieldLine[i].end.x, 1 + m_pSrcFieldLine[i].end.y);
			}
			for (i = 0; i < m_nNumLine; i++)
			{
				pSrcDC->Ellipse(1 + m_pSrcFieldLine[i].start.x - 3, 1 + m_pSrcFieldLine[i].start.y - 3, 
						1 + m_pSrcFieldLine[i].start.x - 3 + 6, 1 + m_pSrcFieldLine[i].start.y - 3 + 6);
				pSrcDC->Ellipse(1 + m_pSrcFieldLine[i].end.x - 3, 1 + m_pSrcFieldLine[i].end.y - 3, 
						1 + m_pSrcFieldLine[i].end.x - 3 + 6, 1 + m_pSrcFieldLine[i].end.y - 3 + 6);
			}

			//break;
		}
	}

	pSrcDC->SelectObject(pOldPen);
	pDestDC->SelectObject(pOldPen);
}


void CMorphingDlg::OnRadioMesh() 
{
	m_nMorphStep = 0;
	if(m_bOpened)
	{
		Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
		Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
	}
	m_nMode = MODE_MESH;
	m_nNumLine = 0;
	m_nSelected = -1;
	m_nMorphStep = 0;

	m_strStep.Format("%d", m_nMorphStep);
	UpdateData(false);
	Invalidate(true);
}

void CMorphingDlg::OnRadioField() 
{
	m_nMorphStep = 0;
	if(m_bOpened)
	{
		Draw(m_pSrcBackDC, m_pSrcIMG, 1, 1);
		Draw(m_pDestBackDC, m_pDestIMG, 1, 1);
	}
	m_nMode = MODE_FIELD;
	m_nNumLine = 0;
	m_nSelected = -1;
	m_nMorphStep = 0;

	m_strStep.Format("%d", m_nMorphStep);
	UpdateData(false);
	Invalidate(true);
}
