// oglview.cpp : implementation of the OGLView class
//

#include "stdafx.h"
#include "OGLApp.h"

#include "ogldoc.h"
#include "oglview.h"
#include "stretchdlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

OGLView * g_view = 0;
StretchDLG g_dlg;
extern CStatusBar * g_status_bar;

/////////////////////////////////////////////////////////////////////////////
// OGLView

IMPLEMENT_DYNCREATE(OGLView, CView)

BEGIN_MESSAGE_MAP(OGLView, CView)
	//{{AFX_MSG_MAP(OGLView)
	ON_WM_SIZE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_VIEW_DRAW_LINES, OnDrawLines)
	ON_UPDATE_COMMAND_UI(ID_VIEW_DRAW_LINES, OnUpdateLines)
	ON_COMMAND(ID_VIEW_DRAW_SOLID, OnDrawSolid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_DRAW_SOLID, OnUpdateSolid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SCALE, OnUpdateScale)
	ON_COMMAND(ID_VIEW_SCALE, OnViewScale)
	ON_UPDATE_COMMAND_UI(ID_VIEW_AXES, OnUpdateAxes)
	ON_COMMAND(ID_VIEW_AXES, OnViewAxes)
	ON_UPDATE_COMMAND_UI(ID_VIEW_EARTH, OnUpdateEarth)
	ON_COMMAND(ID_VIEW_EARTH, OnViewEarth)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SOLAR, OnUpdateSolarSystem)
	ON_COMMAND(ID_VIEW_SOLAR, OnViewSolarSystem)
	ON_WM_RBUTTONDOWN()
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// OGLView construction/destruction

OGLView::OGLView()
{
	m_left_down = 0;
	g_view = this;
}

OGLView::~OGLView()
{
}

BOOL OGLView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// OGLView drawing

void OGLView::OnDraw(CDC* pDC)
{
	OGLDoc* pDoc = GetDocument();
	
	if (pDC->IsPrinting())
	{
		if (m_3dview.IsInitialized())
		{
			UINT32 wpix = pDC->GetDeviceCaps(HORZRES);
			UINT32 hpix = pDC->GetDeviceCaps(VERTRES);
			if ((wpix > 0) && (hpix > 0))
			{
				m_3dview.RebuildModel();
				m_3dview.SizeImage(wpix,hpix);
				  // we really don't want to print with a black
				  // background...right?
				m_3dview.SetBackgroundColor(1.0,1.0,1.0);

				m_3dview.RenderImage();
				glFlush();

				DIBSection * dib = m_3dview.GetDIB();
				if (dib)
				{
					BeginWaitCursor();
					pDC->BitBlt(0,0,wpix,hpix,dib->GetDC(),0,0,SRCCOPY);
					EndWaitCursor();
				}
			}
		}
	}
	else
	{
		ShowImage();
	}
}

void OGLView::ShowImage(void)
{
	if (m_3dview.IsInitialized())
	{
		m_3dview.SetBackgroundColor(0.0,0.0,0.0);
		m_3dview.RenderImage();
		m_3dview.DrawImage(this);
	}

	if (g_status_bar)
	{
		g_status_bar->SetPaneText(0,"Left-mouse-drag to rotate, right-mouse to pick");
	}
}

/////////////////////////////////////////////////////////////////////////////
// OGLView printing

BOOL OGLView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void OGLView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void OGLView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// OGLView diagnostics

#ifdef _DEBUG
void OGLView::AssertValid() const
{
	CView::AssertValid();
}

void OGLView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

OGLDoc* OGLView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(OGLDoc)));
	return (OGLDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// OGLView message handlers

void OGLView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	if (!m_3dview.IsInitialized())
	{
		CRect r;
		GetClientRect(&r);
		m_3dview.CreateImage(r.Width(),r.Height());
		m_3dview.RebuildModel();
	}
	
	g_dlg.Create(IDD_SCALE_DLG, this);
	g_dlg.ShowWindow(SW_SHOW);

	CFrameWnd * frm = GetParentFrame();
	if (frm)
	{
		CRect wr, dr;
		frm->GetWindowRect(&wr);
		g_dlg.GetWindowRect(&dr);

		int left = wr.left - dr.Width() - 1;
		int top = dr.top;
		if (left < 0)
			left = wr.right + 1;
		g_dlg.SetWindowPos(&wndTop,left,top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);
	}
}

void OGLView::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);
	
	if ((cx > 0) && (cy > 0))
	{
		CRect r;
		GetClientRect(&r);
		m_3dview.SizeImage(r.Width(),r.Height());
		m_3dview.RebuildModel();
		ShowImage();
	}
}

void OGLView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	m_click_pt = point;
	m_left_down = 1;
	m_view_matrix = m_3dview.GetModelState();
	
	CView::OnLButtonDown(nFlags, point);
}

void OGLView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	m_left_down = 0;
	
	CView::OnLButtonUp(nFlags, point);
}

void OGLView::OnMouseMove(UINT nFlags, CPoint point) 
{
	if (m_left_down)
	{
		int xdiff = point.x - m_click_pt.x;
		int ydiff = point.y - m_click_pt.y;

		double yrot = xdiff/3.0;
		double xrot = ydiff/3.0;
		double zrot = 0.0;

		while (xrot < 0.0) xrot += 360.0;
		while (xrot > 360.0) xrot -= 360.00000001;

		while (yrot < 0.0) yrot += 360.0;
		while (yrot > 360.0) yrot -= 360.00000001;

		Matrix3D mat = m_view_matrix;
		mat.AddRotation(xrot,yrot,zrot);

		m_3dview.SetModelState(mat);

		ShowImage();
	}
	
	CView::OnMouseMove(nFlags, point);
}

void OGLView::SetScale(double sf)
{
	Matrix3D mat = m_3dview.GetModelState();
	mat.SetScale(sf,sf,sf);
	m_3dview.SetModelState(mat);
	ShowImage();
}

void OGLView::OnDrawLines() 
{
	m_3dview.SetDrawingMode(OGL3D::DrawLines);
	m_3dview.RebuildModel();
	ShowImage();
}

void OGLView::OnUpdateLines(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
	pCmdUI->SetCheck( ( m_3dview.GetDrawingMode() == OGL3D::DrawLines ) ? 1 : 0 );
}

void OGLView::OnDrawSolid() 
{
	m_3dview.SetDrawingMode(OGL3D::DrawTriangles);
	m_3dview.RebuildModel();
	ShowImage();
}

void OGLView::OnUpdateSolid(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
	pCmdUI->SetCheck( ( m_3dview.GetDrawingMode() == OGL3D::DrawLines ) ? 0 : 1 );
}

void OGLView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	OGLDoc * doc = GetDocument();
	if (doc)
	{
		DIBSection * dib = doc->GetDIB();
		if (dib && dib->IsCreated())
		{
			// debugging purposes only
			//CClientDC dc(this);
			//dib->Draw(&dc,0,0);

#ifndef SOLAR
			m_3dview.SetTexture(*dib);
#endif
			m_3dview.RebuildModel();
			ShowImage();

			// more debugging
			//m_3dview.GetTextureDIB()->Draw(&dc,0,0);
		}
	}
}

void OGLView::OnUpdateScale(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
	pCmdUI->SetCheck(g_dlg.IsWindowVisible());
}

void OGLView::OnViewScale() 
{
	g_dlg.ShowWindow(!g_dlg.IsWindowVisible());
}

void OGLView::OnUpdateAxes(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
}

void OGLView::OnViewAxes() 
{	
}

void OGLView::OnUpdateEarth(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
}

void OGLView::OnViewEarth() 
{	
}

void OGLView::OnUpdateSolarSystem(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
}

void OGLView::OnViewSolarSystem() 
{	
}

void OGLView::OnRButtonDown(UINT nFlags, CPoint point) 
{
#ifdef SOLAR
	CString msg;
	m_3dview.PickPlanet(point.x,point.y,msg);
	//m_3dview.DrawImage(this);
	AfxMessageBox((LPCTSTR)msg,MB_ICONINFORMATION);
#endif

	CView::OnRButtonDown(nFlags, point);
}
