// Rasterizer.cpp: implementation of the CRasterizer class.
//
//////////////////////////////////////////////////////////////////////

#include "Rasterizer.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CRasterizer::CRasterizer()
{
	m_pszClassName = "CRasterizer";

	///////////////////////////////////////////////////////////////////////////
	m_hDC = NULL;
	m_hRC = NULL;
}

CRasterizer::~CRasterizer()
{
	Destroy();
}

void CRasterizer::Destroy()
{
	// Destroy OpenGL
	if (m_hRC)
	{
		DestroyOpenGL(m_hRC);
		m_hRC = NULL;
	}
}

bool CRasterizer::Create(HDC hDC)
{
	m_hDC = hDC;

	// Create OpenGL
	m_hRC = CreateOpenGL(m_hDC);
	if (!m_hRC)
		return false;

	return true;
}

void CRasterizer::Initialize()
{
	glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
	glClearDepth(1.0f);

	glDisable(GL_BLEND);
	glDisable(GL_DEPTH);
    glDisable(GL_DITHER);

	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);

	// Perform hidden line/surface removal (enabling Z-Buffer)
	glEnable(GL_DEPTH_TEST);

	// Set DepthFunc to LEQUAL or it will not pass depth test
	glDepthFunc(GL_LEQUAL);

	// Enable Culling
	glEnable(GL_CULL_FACE);

	//glFrontFace(GL_CCW);
	//glCullFace(GL_FRONT);

	glFrontFace(GL_CW);
	glCullFace(GL_BACK);

	// Smooth Shading
	glShadeModel(GL_SMOOTH);
/*
	///////////////////////////////////////////////////////////////////////////
	// Setup the color material
	glColorMaterial(GL_FRONT, GL_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL);

	// Setup the lights
	glEnable(GL_LIGHTING);

	GLfloat lightA[4] = {0.2F, 0.2F, 0.2F, 1.0F};
	GLfloat lightD[4] = {0.8F, 0.8F, 0.8F, 1.0F};
	GLfloat lightS[4] = {0.1F, 0.1F, 0.1F, 1.0F};
	GLfloat lightP[4] = { 0.0F, 0.0F, 10.0F, 1.0F };

	glEnable(GL_LIGHT0);

	glLightfv(GL_LIGHT0, GL_DIFFUSE,  lightD);
	glLightfv(GL_LIGHT0, GL_SPECULAR, lightS);
	glLightfv(GL_LIGHT0, GL_AMBIENT,  lightA);
	glLightfv(GL_LIGHT0, GL_POSITION, lightP);

	glLightf(GL_LIGHT0, GL_SHININESS, 128.0f);
	///////////////////////////////////////////////////////////////////////////
*/
	// Enable Texture
	glEnable(GL_TEXTURE_2D);

	// Enable Alpha Test
	//glEnable(GL_ALPHA_TEST);
    //glAlphaFunc(GL_GREATER, 0.1f);
	//glAlphaFunc(GL_GREATER, .01f);

	//glEnable(GL_BLEND);

	//glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// Enable Extensions
	///////////////////////////////////////////////////////////////////////////

	//glPolygonMode(GL_FRONT, GL_FILL);
	//glPolygonMode(GL_FRONT, GL_LINE);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
	//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	//glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
}

void CRasterizer::SetViewport(LONG x, LONG y, LONG width, LONG height)
{
	glViewport(x, y, width, height);
}

void CRasterizer::BeginScene()
{
	// Clear Color Buffer & Depth Buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glPushMatrix();
}

void CRasterizer::EndScene()
{
	glPopMatrix();
	
	// Finish Render
	glFinish();

	// Swap Buffers ( double buffer )
	wglSwapBuffers(m_hDC);
}

void CRasterizer::SetPerspective(LONG width, LONG height)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
/*
	#define FOVY	20.0f

	GLdouble aspect = (GLdouble) width / (GLdouble) height;
	GLdouble right  = sin( FOVY/2.0 *PI/180.0f );
	GLdouble top    = right / aspect;
	GLdouble bottom = -top;
	GLdouble left   = -right;

	glFrustum(left, right, bottom, top, 4.0f, 100000.0f);
*/


	//float xf = (float) m_iWidth / (float) m_iHeight;
	//glFrustum(-4.0f, 4.0f, -2.605f*xf, 2.605f*xf, 6.0f, 25000.0f);


	//GLdouble aspect = (GLfloat) m_iWidth / (GLfloat) m_iHeight;
    //gluPerspective(FOVY, aspect, 4.0f, 4096.0f);


	// GLQuake Mode
	//glFrustum(-4.0f, 4.0f, -2.704225f, 2.704225f, 4.0f, 4096.0f);


	float xmin, xmax, ymin, ymax, ratio, zNear = 1.0, zFar = 5000.0;

	float angle = 45.0f;
	ymax = zNear * (float) tan(angle * (float) PI / 360.0f);
	ymin = -ymax;

	if (width > height)
		ratio = (float) width / (float) height;
	else
		ratio = (float) height / (float) width;

	xmin = ymin * ratio;
	xmax = ymax * ratio;

	glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void CRasterizer::SetOrtho(LONG width, LONG height)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

bool CRasterizer::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, USHORT bitsPerPel)
{
	HDC hDC = GetDC(NULL);
	bitsPerPel = GetDeviceCaps(hDC, BITSPIXEL);
	ReleaseDC(NULL, hDC);

	DEVMODE dm;

	dm.dmPelsWidth        = dwWidth;
	dm.dmPelsHeight       = dwHeight;
	dm.dmBitsPerPel       = bitsPerPel;
	dm.dmDisplayFrequency = 0;
	dm.dmFields           = DM_BITSPERPEL | 
		                    DM_PELSWIDTH | 
							DM_PELSHEIGHT | 
							DM_DISPLAYFREQUENCY;
    
	//if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
	if (ChangeDisplaySettings(&dm, NULL) == DISP_CHANGE_SUCCESSFUL)
		return true;

	return false;
}

void CRasterizer::RestoreDisplayMode()
{
	ChangeDisplaySettings(NULL, 0);
}

