/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	Please read the file LICENSE.TXT for additional details.


	source:
		OpenGL windows implementation

	revision history:
		Apr/22/2001 - Jukka Liimatta - initial revision
*/
#include <prcore/prcore.hpp>
#include <GL/gl.h>

using namespace prcore;



struct ContextWGL
{
	HDC		hdc;
	HGLRC	hrc;
};


static Array<ModeGL> ModeList;


static void EnumModeList()
{
	DEVMODE devmode;

	for ( int index=0; EnumDisplaySettings(NULL,index,&devmode); ++index )
	{
		// reject indexed pixelformats
		if ( devmode.dmBitsPerPel > 8 )
		{
			ModeGL mode;

			mode.width = devmode.dmPelsWidth;
			mode.height = devmode.dmPelsHeight;
			mode.bits = devmode.dmBitsPerPel;
			mode.frequency = devmode.dmDisplayFrequency;

			ModeList.PushBack(mode);
		}
	}
}


WindowGL::WindowGL()
{
	if ( !ModeList.GetSize() )
	{
		EnumModeList();
	}
}


WindowGL::~WindowGL()
{
	RestoreMode();
}


int WindowGL::GetModeCount() const
{
	return ModeList.GetSize();
}


ModeGL WindowGL::GetMode(int index) const
{
	assert( index>=0 && index<= ModeList.GetSize() );
	return ModeList[index];
}


bool WindowGL::SetMode(const ModeGL& mode)
{
	DEVMODE devmode;

	devmode.dmSize = sizeof(DEVMODE);
	devmode.dmDriverExtra = 0;
	devmode.dmBitsPerPel = mode.bits;
	devmode.dmPelsWidth = mode.width;
	devmode.dmPelsHeight = mode.height;
	devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

	if ( mode.frequency )
	{
		devmode.dmDisplayFrequency = mode.frequency;
		devmode.dmFields |= DM_DISPLAYFREQUENCY;
	}

	return ChangeDisplaySettings(&devmode,CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL ? false : true;
}


bool WindowGL::RestoreMode()
{
	return ChangeDisplaySettings(NULL,0) != DISP_CHANGE_SUCCESSFUL ? 
		false : true;
}


ContextGL* WindowGL::CreateContext(InitGL* init)
{
	// do we have a rendering window?
	HWND hwnd = mWinHandle.hwnd;
	if ( !hwnd )
		return NULL;

	PIXELFORMATDESCRIPTOR pfd;
	pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 32;
	pfd.cAccumBits = 0;
	pfd.cDepthBits = 24;
	pfd.cStencilBits = 8;
	pfd.dwLayerMask = PFD_MAIN_PLANE;

	if ( init )
	{
		pfd.cColorBits = init->color;
		pfd.cAccumBits = init->accum;
		pfd.cDepthBits = init->depth;
		pfd.cStencilBits = init->stencil;
	}

	// get device context
	HDC hdc = GetDC(hwnd);

	// set pixelformat
	int index = ChoosePixelFormat(hdc,&pfd);
	SetPixelFormat(hdc,index,&pfd);

	// create gl render context
	HGLRC hrc = wglCreateContext(hdc);

	ContextWGL* context = new ContextWGL();
	context->hdc = hdc;
	context->hrc = hrc;

	return (ContextGL*)context;
}


void WindowGL::DeleteContext(ContextGL* context)
{
	ContextWGL* ctx = (ContextWGL*)context;

	wglDeleteContext(ctx->hrc);
	delete ctx;

	if ( mCurrentContext == context )
	{
		wglMakeCurrent(NULL,NULL);
		mCurrentContext = NULL;
	}
}


void WindowGL::SetContext(ContextGL* context)
{
	ContextWGL* ctx = (ContextWGL*)context;
	if ( ctx )
		wglMakeCurrent(ctx->hdc,ctx->hrc);
		
	mCurrentContext = context;
}


void WindowGL::PageFlip(bool retrace)
{
	ContextWGL* ctx = (ContextWGL*)mCurrentContext;
	if ( ctx )
		SwapBuffers(ctx->hdc);
}
