#include "stdafx.h"

#include "SysObj.hpp"



// --------------------------------------------------------------------------------------------
// BEGIN window details
// --------------------------------------------------------------------------------------------

// Small structure that holds window width and height choices
struct vmode_t { int w; int h; };

// Number of modes supported
int numResModes = 12;

// This array determines which of the vmodes tested ok 0=fail 1=pass
int	validres[12];

// Definition of all the video modes
struct vmode_t vmodes[] =	{
		{  320, 200   },		{  320, 240   },
		{  400, 300   },		{  480, 360   },
		{  512, 384   },		{  640, 480   },
		{  800, 600   },		{  960, 720   },
		{  1024, 768  },		{  1152, 864  },
		{  1280, 960  },		{  1280, 1024 }
		};

// --------------------------------------------------------------------------------------------
// END window details
// --------------------------------------------------------------------------------------------

  



/*	Some of the things that can be done with the window
			        Tytle,          Win width_height      PFD > 0

	// Open the window first
	ge.openWindow( " Window Title Bar", v640_480, FULLSCREEN, 1 );
	ge.openWindow( " THE MONSTER GAME ", v640_480, WINDOWED, 1 );
	 
	// after that change the resolution to anything you like as much as you like
	ge.changeResolution ( v1024_768 );
	ge.changeResolution ( v800_600 );

	// make the window smaller than the resolution ( makes it appear windowed )
	// as much as you like
	ge.changeWindow ( ((640-300)/2), ((480-200)/2), 300, 200, v640_480 );
*/





// --------------------------------------------------------------------------------------------
// BEGIN Window Class Registration
//
// this only happens once during the programs execution
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------
int sys::regClass ( WNDPROC MainWndProc , HINSTANCE hInst, char *className) {
	WNDCLASSEX	wndClassx;


	// If a class had been registered, then dont register any more classes
	if ( this->classActive ) {
		return CLASS_ALREADY_REGISTERED;
	}

	// WNDCLASSEX is the class definition structure
	memset( &wndClassx, 0, sizeof(WNDCLASSEX) );

	// populate our class, no special features needed
	wndClassx.cbSize			= sizeof(WNDCLASSEX); 
	wndClassx.style			= CS_HREDRAW | CS_VREDRAW;
	wndClassx.lpfnWndProc		= (WNDPROC)MainWndProc;
	wndClassx.cbClsExtra		= 0;
	wndClassx.cbWndExtra		= 0;
	wndClassx.hInstance		= hInst;
	wndClassx.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndClassx.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wndClassx.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wndClassx.lpszMenuName	= NULL;
	wndClassx.lpszClassName	= className;
	wndClassx.hIconSm			= NULL;

	// Register the class with the operating system
	if (!RegisterClassEx ( &wndClassx ) ) {
		this->hInst = NULL;
		this->classActive = 0;
		this->className = NULL;
		return REGISTER_CLASS_FAILED;
	}

	// If all went well
	this->classActive = true;
	this->className = className;
	this->hInst = hInst;
	return CLASS_REGISTER_SUCCESS;
}
// --------------------------------------------------------------------------------------------
// END Window Class Registration
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Change monitor resolution
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

int sys::changeResolution (int resId ) {
	DEVMODE devmode;
	int val;

	// Grab a copy of current video configuration
	EnumDisplaySettings (NULL, 0, &devmode);

	// Insert new resolution parameters
	devmode.dmPelsWidth = vmodes[resId].w;
	devmode.dmPelsHeight = vmodes[resId].h;

	// Tell the system to Only apply the new width and height
	devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

	// Ask system to change monitor resolution on the fly, CDS_FULLSCREEN = temporary reversable change
	val = ChangeDisplaySettings(&devmode, CDS_FULLSCREEN);
	
	// See what went wrong, IF it went wrong at all
	switch ( val ) {
	case DISP_CHANGE_RESTART:
		fprintf(fp,"\nThe computer must be restarted in order for the graphics mode to work.\n");
		break;
	case DISP_CHANGE_BADFLAGS:
		fprintf(fp,"\nAn invalid set of flags was passed in.\n");
		break;
	case DISP_CHANGE_FAILED:
		fprintf(fp,"\nThe display driver failed the specified graphics mode.\n");
		break;
	case DISP_CHANGE_BADMODE:
	case DISP_CHANGE_BADPARAM:
		fprintf(fp,"\nThe graphics mode is not supported.\n");
		break;
	case DISP_CHANGE_NOTUPDATED:
		fprintf(fp,"\nUnable to write settings to the registry.\n");
		break;
	case DISP_CHANGE_SUCCESSFUL:
		fprintf(fp,"\n Change Resolution Success.\n");
		break;
	default:
		fprintf(fp,"Unknown error: %d\n", val);
		break;
	}

	// return a result
	if (val == DISP_CHANGE_SUCCESSFUL )
		return MONITOR_RESOLUTION_CHANGED_OK;
	else
		return MONITOR_RESOLUTION_FAILURE;
}
// --------------------------------------------------------------------------------------------
// END Change monitor resolution
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Window Create
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

int sys::openWindow ( char *winTitle ,int resId, int resType, int pfdType) {

	int errCode;

	// this is the base opengl window styles
	DWORD baseStyles	= WS_POPUP  | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	// additional styles for windowed mode
	DWORD windowStyles	= WS_BORDER | WS_CAPTION;

	// Only one window alowed
	if ( this->hWnd )
		return WINDOW_EXISTS;

	// set the monitor hardware resolution to match the window size when goin full screen
	if ( resType == FULLSCREEN )
		errCode = changeResolution ( resId );

	// if any problems then return
	if ( errCode == MONITOR_RESOLUTION_FAILURE )
		return MONITOR_RESOLUTION_FAILURE;

	// if its not full screen mode then add window border and tytle bar
	if ( resType == WINDOWED )
		baseStyles = baseStyles | windowStyles;

	// create the window now
   this->hWnd = CreateWindow (
	   
		this->className,
		winTitle,
		baseStyles,
		0,
		0,
		vmodes[resId].w,
		vmodes[resId].h,
		NULL,
		NULL,
		this->hInst,
		NULL
		
		);
   

   // if we have the window up and running make it show
   if ( this->hWnd )
	{
		ShowWindow ( this->hWnd, SW_SHOW );
		UpdateWindow ( this->hWnd );

		// probe pixel formats and resolutions to see which are useful and valid
		errCode = probeVideo();
		if ( errCode != VIDEO_USABLE )
			return errCode;

		// set the apropriate pixel mode and enable opengl rendering
		errCode = setMode ( pfdType );

		if ( errCode == RENDERING_CONTEXT_IS_LIVE )
			return CREATE_WINDOW_OK;
		else
			return errCode;
	}
   else
	{
		return CREATE_WINDOW_FAIL;
	}
};

// --------------------------------------------------------------------------------------------
// END Window Create
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Probe video pixelformats and resolutions applicable for OPENGL
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------

	int sys::probeVideo ( void ) {

		int usableResCount=0;
		DEVMODE devmode;
		int i,n;
		int count;
		int iPF;
		int maxPF;
		PIXELFORMATDESCRIPTOR pfray;
	

		// Need to get the Device Context of this window
		this->hDc = GetDC(this->hWnd);
		if ( this->hDc == NULL )
			return FAILED_TO_GETDC;

		fprintf (fp, "\n Detecting Pixel Formats Available \n\n\n");


		// detect how many pix formats available that suit our purpose
		maxPF = dll._wglDescribePixelFormat(hDc, 1, 0, NULL);
		if ( maxPF == 0 )
			return NO_PIXEL_FORMATS;

		this->goodpfCount=0;

		// scan all pixel formats for suitability
		for ( iPF = maxPF, count = 0; iPF >= 1; iPF-- ) {

			dll._wglDescribePixelFormat(hDc, iPF, sizeof(PIXELFORMATDESCRIPTOR), &pfray );

			// make sure it meets a few requirements for our opengl usage
			if(pfray.cColorBits < 16)
				continue;
			if(pfray.cDepthBits < 8)
				continue;
			if(!(pfray.dwFlags & PFD_DOUBLEBUFFER))
				continue;
			if(!(pfray.dwFlags & PFD_SUPPORT_OPENGL))
				continue;
			if(pfray.iPixelType != PFD_TYPE_RGBA)
				continue;

			fprintf (fp, "DBLBUFFER    OPENGL    ");
			fprintf (fp,"ColorBits: %d    DepthBits: %d    " , pfray.cColorBits , pfray.cDepthBits );
			if (pfray.iPixelType == PFD_TYPE_RGBA) fprintf (fp,"PixelType: PFD_TYPE_RGBA \n");
			if (pfray.iPixelType == PFD_TYPE_COLORINDEX) fprintf (fp,"PixelType: PFD_TYPE_COLORINDEX \n");

			// remember the system offset for these good pixel formats
			goodpf[goodpfCount] = iPF;
			goodpfCount++;

			count++;
		}

		// make sure we get atleast one suitable pixel format
		if ( goodpfCount == 0 )
			return NO_SUITABLE_PIXEL_FORMATS;

		fprintf (fp, "\n\n\n Testing Resolutions \n");


		// go test to see what resolutions are available
		for ( i=0; i<numResModes; i++ ) {

			// grab curent view settings
			EnumDisplaySettings ( NULL, 0, &devmode );
			devmode.dmPelsWidth = vmodes[i].w;
			devmode.dmPelsHeight = vmodes[i].h;
			devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

			// use the test mode to see if it may work
			n = ChangeDisplaySettings ( &devmode, CDS_TEST );
		

			// mark the resolutions that seem to be ok
			if ( n == DISP_CHANGE_SUCCESSFUL ) {
				validres[i] = 1;
				usableResCount++;			
				fprintf (fp, "PASSED  %d  X  %d \n", vmodes[i].w, vmodes[i].h );
			}
			else {
				validres[i] = 0;
				fprintf (fp, "FAILED  %d  X  %d \n", vmodes[i].w, vmodes[i].h );

			}
		}

		if ( usableResCount == 0 )
			return LACK_OF_RESOLUTIONS;

		return VIDEO_USABLE;
	}
// --------------------------------------------------------------------------------------------
// END Probe video pixelformats and resolutions applicable for OPENGL
// --------------------------------------------------------------------------------------------

  














// --------------------------------------------------------------------------------------------
// BEGIN Print error code
//
// Created:		Monday 6th November 2000
// Last Change: Monday 6th November 2000
// --------------------------------------------------------------------------------------------
void sys::print ( char *format, ... ) {
	va_list ap;
	static char strtmp[1024];

	va_start(ap, format);
		_vsnprintf(strtmp, sizeof(strtmp), format, ap);
	va_end(ap);

	fwrite(strtmp, 1, strlen(strtmp), fp);
	fflush(fp);

}
// --------------------------------------------------------------------------------------------
// END Print
// --------------------------------------------------------------------------------------------
















// --------------------------------------------------------------------------------------------
// BEGIN Set rendering context
//
// Created:		Friday 3rd November 2000
// Last Change: Sunday 5th November 2000
// --------------------------------------------------------------------------------------------
int sys::setMode ( int pfdId ) {
	PIXELFORMATDESCRIPTOR wpfd;
	int errCode;

	// grab current format
	errCode = dll._wglDescribePixelFormat(this->hDc, pfdId, sizeof(PIXELFORMATDESCRIPTOR), &wpfd);
	
	if ( errCode == 0 )
		return COULD_NOT_DESCRIBE_PIXEL_FORMAT;

	// try to apply a new format
	if (!dll._wglSetPixelFormat(this->hDc, goodpf[pfdId], &wpfd)) {
		fprintf (fp, "\n\n Error applying pixel format" );
		return COULD_NOT_SET_PIXEL_FORMAT;
	}


	fprintf (fp, "\n\n Applied pixel format " );

	// Create rendering context	
	this->hRc = dll._wglCreateContext(this->hDc);
	if ( this->hRc == NULL ) {
		fprintf (fp, "\n\n Error Creating Gl context");
		return COULD_NOT_CREATE_CONTEXT;
	} else {
		fprintf (fp, "\n\n Created Gl context");
	}

	// Make it usable
	if( !dll._wglMakeCurrent (this->hDc, this->hRc) ) {
		fprintf (fp, "\n\n Error MakeCurrent ");
		return COULD_NOT_MAKE_RC_CURRENT;
	} else {
		fprintf (fp, "\n\n MakeCurrent succeded");
	}

		
	return RENDERING_CONTEXT_IS_LIVE;

}
// --------------------------------------------------------------------------------------------
// END rendering context
// --------------------------------------------------------------------------------------------


int sys::changeWindow ( int x, int y, int width, int height, int resId ) {
	int errCode;

	// change to the new monitor resolution
	errCode = changeResolution ( resId );

		// return a result
	if ( errCode == DISP_CHANGE_SUCCESSFUL )
		return MONITOR_RESOLUTION_CHANGED_OK;
	else
		return MONITOR_RESOLUTION_FAILURE;


	// now update the window 
	errCode = SetWindowPos ( this->hWnd, HWND_TOP, x, y, width, height, SWP_SHOWWINDOW );

	// any errors
	if ( errCode == 0 )
		return COULD_NOT_CHANGE_WINDOW;

	return OK;
}






