// IslandView.cpp : implementation of the CIslandView class
//

#include "stdafx.h"
#include "Island.h"

#include "IslandDoc.h"
#include "IslandView.h"
#include "IslandWorld.h"

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

/////////////////////////////////////////////////////////////////////////////
// CIslandView

IMPLEMENT_DYNCREATE(CIslandView, CView)

BEGIN_MESSAGE_MAP(CIslandView, CView)
	//{{AFX_MSG_MAP(CIslandView)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_QUERYNEWPALETTE()
	ON_WM_PALETTECHANGED()
	ON_WM_ERASEBKGND()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_COMMAND(ID_WEATHER_FOGGY, OnWeatherFoggy)
	ON_UPDATE_COMMAND_UI(ID_WEATHER_FOGGY, OnUpdateWeatherFoggy)
	ON_COMMAND(ID_WEATHER_SUNNY, OnWeatherSunny)
	ON_UPDATE_COMMAND_UI(ID_WEATHER_SUNNY, OnUpdateWeatherSunny)
	ON_COMMAND(ID_TEXTURES_USETEXTURES, OnTexturesUsetextures)
	ON_UPDATE_COMMAND_UI(ID_TEXTURES_USETEXTURES, OnUpdateTexturesUsetextures)
	ON_COMMAND(ID_CAMERA_GOD, OnCameraGod)
	ON_UPDATE_COMMAND_UI(ID_CAMERA_GOD, OnUpdateCameraGod)
	ON_COMMAND(ID_CAMERA_MAN, OnCameraMan)
	ON_UPDATE_COMMAND_UI(ID_CAMERA_MAN, OnUpdateCameraMan)
	ON_COMMAND(ID_CAMERA_WOMAN, OnCameraWoman)
	ON_UPDATE_COMMAND_UI(ID_CAMERA_WOMAN, OnUpdateCameraWoman)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CIslandView construction/destruction

CIslandView::CIslandView()
{
	// TODO: add construction code here

}

CIslandView::~CIslandView()
{
}

BOOL CIslandView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	// Add Window styles required for OpenGL before window is created
	cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_OWNDC);

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CIslandView drawing

void CIslandView::OnDraw(CDC* pDC)
{
	CIslandDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	// TODO: add draw code for native data here
	wglMakeCurrent(m_hDc,m_hRc);

	pDoc->DrawScene();

	// Swap our scene to the front
	SwapBuffers(m_hDc);

	// Allow other rendering contexts to co-exist
	//wglMakeCurrent(m_hDc,NULL);
}

/////////////////////////////////////////////////////////////////////////////
// CIslandView diagnostics

#ifdef _DEBUG
void CIslandView::AssertValid() const
{
	CView::AssertValid();
}

void CIslandView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CIslandDoc* CIslandView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CIslandDoc)));
	return (CIslandDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CIslandView message handlers

int CIslandView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	// TODO: Add your specialized creation code here
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	int nPixelFormat;					// Pixel format index
	m_hDc = ::GetDC(m_hWnd);			// Get the Device context

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),	// Size of this structure
		1,								// Version of this structure	
		PFD_DRAW_TO_WINDOW |			// Draw to Window (not to bitmap)
		PFD_SUPPORT_OPENGL |			// Support OpenGL calls in window
		PFD_DOUBLEBUFFER,				// Double buffered mode
		PFD_TYPE_RGBA,					// RGBA Color mode
		24,								// Want 24bit color 
		0,0,0,0,0,0,					// Not used to select mode
		0,0,							// Not used to select mode
		0,0,0,0,0,						// Not used to select mode
		32,								// Size of depth buffer
		0,								// Not used to select mode
		0,								// Not used to select mode
		PFD_MAIN_PLANE,					// Draw in main plane
		0,								// Not used to select mode
		0,0,0 };						// Not used to select mode

	// Choose a pixel format that best matches that described in pfd
	nPixelFormat = ChoosePixelFormat(m_hDc, &pfd);

	// Set the pixel format for the device context
	VERIFY(SetPixelFormat(m_hDc, nPixelFormat, &pfd));

	// Create the rendering context
	m_hRc = wglCreateContext(m_hDc);

	// Make the rendering context current, perform initialization, then
	// deselect it
	VERIFY(wglMakeCurrent(m_hDc,m_hRc));
	CIslandDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	pDoc->CreateIsland();
	wglMakeCurrent(NULL,NULL);

	// Create the palette if needed
	InitializePalette();
	
	return 0;
	
}

void CIslandView::OnDestroy() 
{
	CView::OnDestroy();
	
	// TODO: Add your message handler code here
	// Clean up rendering context stuff
	wglDeleteContext(m_hRc);
	::ReleaseDC(m_hWnd,m_hDc);
}

void CIslandView::InitializePalette()
{
	PIXELFORMATDESCRIPTOR pfd;	// Pixel Format Descriptor
	LOGPALETTE *pPal;			// Pointer to memory for logical palette
	int nPixelFormat;			// Pixel format index
	int nColors;				// Number of entries in palette
	int i;						// Counting variable
	BYTE RedRange,GreenRange,BlueRange;
								// Range for each color entry (7,7,and 3)

	// Get the pixel format index and retrieve the pixel format description
	nPixelFormat = GetPixelFormat(m_hDc);
	DescribePixelFormat(m_hDc, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

	// Does this pixel format require a palette?  If not, do not create a
	// palette and just return NULL
	if(!(pfd.dwFlags & PFD_NEED_PALETTE))
		return;

	// Number of entries in palette.  8 bits yeilds 256 entries
	nColors = 1 << pfd.cColorBits;	

	// Allocate space for a logical palette structure plus all the palette entries
	pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));

	// Fill in palette header 
	pPal->palVersion = 0x300;		// Windows 3.0
	pPal->palNumEntries = nColors; // table size

	// Build mask of all 1's.  This creates a number represented by having
	// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
	// pfd.cBlueBits.  
	RedRange = (1 << pfd.cRedBits) -1;
	GreenRange = (1 << pfd.cGreenBits) - 1;
	BlueRange = (1 << pfd.cBlueBits) -1;

	// Loop through all the palette entries
	for(i = 0; i < nColors; i++)
		{
		// Fill in the 8-bit equivalents for each component
		pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
		pPal->palPalEntry[i].peRed = (unsigned char)(
			(double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);

		pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
		pPal->palPalEntry[i].peGreen = (unsigned char)(
			(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);

		pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
		pPal->palPalEntry[i].peBlue = (unsigned char)(
			(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);

		pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
		}
		
	// Create the palette
	m_GLPalette.CreatePalette(pPal);

	// Go ahead and select and realize the palette for this device context
	SelectPalette(m_hDc,(HPALETTE)m_GLPalette,FALSE);
	RealizePalette(m_hDc);

	// Free the memory used for the logical palette structure
	free(pPal);
}

void CIslandView::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	GLsizei width, height;
	GLdouble aspect;

	width = cx;
	height = cy;

	if (cy==0)
		aspect = (GLdouble)width;
	else
		aspect = (GLdouble)width/(GLdouble)height;

	wglMakeCurrent(m_hDc,m_hRc);

	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	// Establish viewing volume
	gluPerspective(45.0, aspect,1, 2000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glDrawBuffer(GL_BACK);
	glEnable(GL_DEPTH_TEST);
	wglMakeCurrent(NULL,NULL);
}

//keeps the bakcground from being erased every time the window
//is repainted.
BOOL CIslandView::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	return FALSE;
}

BOOL CIslandView::OnQueryNewPalette() 
{
	// If the palette was created.
	if((HPALETTE)m_GLPalette)
	{
		int nRet;

		// Selects the palette into the current device context
		SelectPalette(m_hDc, (HPALETTE)m_GLPalette, FALSE);

		// Map entries from the currently selected palette to
		// the system palette.  The return value is the number 
		// of palette entries modified.
		nRet = RealizePalette(m_hDc);

		// Repaint, forces remap of palette in current window
		InvalidateRect(NULL,FALSE);

		return nRet;
	}

	return CView::OnQueryNewPalette();
}

void CIslandView::OnPaletteChanged(CWnd* pFocusWnd) 
{
	if(((HPALETTE)m_GLPalette != NULL) && (pFocusWnd != this))
	{
		// Select the palette into the device context
		SelectPalette(m_hDc,(HPALETTE)m_GLPalette,FALSE);

		// Map entries to system palette
		RealizePalette(m_hDc);
				
		// Remap the current colors to the newly realized palette
		UpdateColors(m_hDc);
		return;
	}

	CView::OnPaletteChanged(pFocusWnd);
}

void CIslandView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	if (nChar == VK_ESCAPE)
	{
		PostQuitMessage (1);
		return;
	};	
	switch(nChar)
	{
		case VK_UP:
		case VK_RIGHT:
		case VK_DOWN:
		case VK_LEFT:
		case VK_SHIFT:
			//now move the current character, the current camera
			CIslandDoc* pDoc = GetDocument();
			pDoc->KeyPressedInDirection(nChar);
			break;			
	}
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CIslandView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	switch(nChar)
	{
		case VK_SHIFT:
			CIslandDoc* pDoc = GetDocument();
			pDoc->KeyUpInDirection(nChar);
			break;			
	}
	CView::OnKeyUp(nChar, nRepCnt, nFlags);
}

void CIslandView::OnWeatherFoggy() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->SetCurrentIslandWeather(FOGGY);
}

void CIslandView::OnUpdateWeatherFoggy(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandWeather() == FOGGY);
	
}

void CIslandView::OnWeatherSunny() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->SetCurrentIslandWeather(SUNNY);
}

void CIslandView::OnUpdateWeatherSunny(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandWeather() == SUNNY);
}

void CIslandView::OnTexturesUsetextures() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->ToggleCurrentIslandDisplayMethod();
	
}

void CIslandView::OnUpdateTexturesUsetextures(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandDisplayMethod() == TEXTURED);
}

void CIslandView::OnCameraGod() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->ChangeCharacter(GOD);
	
}

void CIslandView::OnUpdateCameraGod(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandCharacter() == GOD);
	
}

void CIslandView::OnCameraMan() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->ChangeCharacter(MAN);
	
}

void CIslandView::OnUpdateCameraMan(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandCharacter() == MAN);
	
}

void CIslandView::OnCameraWoman() 
{
	// TODO: Add your command handler code here
	CIslandDoc* pDoc = GetDocument();
	pDoc->ChangeCharacter(WOMAN);
	
}

void CIslandView::OnUpdateCameraWoman(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	CIslandDoc* pDoc = GetDocument();
	pCmdUI->SetCheck(pDoc->GetCurrentIslandCharacter() == WOMAN);
	
}
