/**
* \file graphics_main.cpp
* \author basile.graf@epfl.ch
* 
* This is the main graphic code. Window management, (main) OpenGL drawing, ...  
*/



#include "graphics_relative.h"

#include "../hydro_source/dataFillings.h"

HGLRC           hRC=NULL;							// Permanent Rendering Context
HDC             hDC=NULL;							// Private GDI Device Context
HWND            hWnd=NULL;							// Holds Our Window Handle
HINSTANCE       hInstance;							// Holds The Instance Of The Application

GLuint	base;							// Base Display List For The Font Set


bool	keys[256];									// Array Used For The Keyboard Routine
bool	active=TRUE;								// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;							// Fullscreen Flag Set To Fullscreen Mode By Default

bool	light;									// Lighting ON / OFF



GLfloat viewAngle1 = 0.0;  ///< horizontal camera view angle
GLfloat viewAngle2 = 0.3;  ///< vertical camera view angle
GLfloat dviewAngle = 0.01;
GLfloat viewDist = 50.0;   ///< camera view distance
GLfloat dviewDist = 0.3;


GLfloat LightAmbient[]= { 0.35f, 0.35f, 0.5f, 1.0f }; 				// Ambient Light Values ( NEW )
GLfloat LightDiffuse[]= { 0.6f, 0.6f, 0.6f, 1.0f };				 // Diffuse Light Values ( NEW )
GLfloat LightPosition[]= { -10.0f, 20.0f, 150.0f, 0.0f };				 // Light Position ( NEW )
//GLfloat LightPosition[]= { 0.0f, -10.0f, 10.0f, 1.0f };				 // Light Position ( NEW )

MSG	msg;								// Windows Message Structure
BOOL	done=FALSE;							// Bool Variable To Exit Loop

//joystick stuff
int joystick_exist;
bool doX = TRUE;	//TRUE: use jostick X-axis, FALSE: use keyboard
bool doY = TRUE;	//TRUE: use jostick Y-axis, FALSE: use keyboard
bool doZ = TRUE;	//TRUE: use jostick Z-axis, FALSE: use keyboard
bool doR = TRUE;	//TRUE: use jostick R-axis, FALSE: use keyboard
bool allowChangeDoX = TRUE; //ON-OFF behaviour
bool allowChangeDoY = TRUE;
bool allowChangeDoZ = TRUE; //ON-OFF behaviour
bool allowChangeDoR = TRUE;
float dirX = 1.0f;  //change axis direction: -1.0f
float dirY = 1.0f;
float dirZ = 1.0f;
float dirR = 1.0f;
bool allowChangeDirX = TRUE; //ON-OFF behaviour
bool allowChangeDirY = TRUE;
bool allowChangeDirZ = TRUE;
bool allowChangeDirR = TRUE;
float time_before = 0.0; //for keyboard controll and fps computing
float time_elapsed; //for keyboard controll and fps computing
float fps = 0.0; //frames per second



/// Create OSD font
/**
* Creates font for OSD (On Screen Display), 
* i.e. displaying various informations on the screen... (Windows dependent)
*/
GLvoid BuildFont(GLvoid)					// Build Our Bitmap Font
{
	HFONT	font;						// Windows Font ID
	HFONT	oldfont;					// Used For Good House Keeping

	base = glGenLists(96);					// Storage For 96 Characters ( NEW )

	font = CreateFont(	-16,				// Height Of Font ( NEW )
				0,				// Width Of Font
				0,				// Angle Of Escapement
				0,				// Orientation Angle
				FW_BOLD,			// Font Weight
				FALSE,				// Italic
				FALSE,				// Underline
				FALSE,				// Strikeout
				ANSI_CHARSET,			// Character Set Identifier
				OUT_TT_PRECIS,			// Output Precision
				CLIP_DEFAULT_PRECIS,		// Clipping Precision
				ANTIALIASED_QUALITY,		// Output Quality
				FF_DONTCARE|DEFAULT_PITCH,	// Family And Pitch
				"Courier New");			// Font Name

	oldfont = (HFONT)SelectObject(hDC, font);		// Selects The Font We Want
	wglUseFontBitmaps(hDC, 32, 96, base);			// Builds 96 Characters Starting At Character 32
	SelectObject(hDC, oldfont);				// Selects The Font We Want
	DeleteObject(font);					// Delete The Font
}


/// Delete font list
/**
* Delete the font list created by BuildFont()
*/
GLvoid KillFont(GLvoid)						// Delete The Font List
{
 	glDeleteLists(base, 96);				// Delete All 96 Characters ( NEW )
}

/// Custom GL "Print" Routine
/**
* A function that can be used like fprint(), but for writing on the OpenGL window
*/
GLvoid glPrint(const char *fmt, ...)				// Custom GL "Print" Routine
{
	char		text[256];				// Holds Our String
	va_list		ap;					// Pointer To List Of Arguments

	if (fmt == NULL)					// If There's No Text
		return;						// Do Nothing
	
	va_start(ap, fmt);					// Parses The String For Variables
	    vsprintf(text, fmt, ap);				// And Converts Symbols To Actual Numbers
	va_end(ap);						// Results Are Stored In Text

	glPushAttrib(GL_LIST_BIT);				// Pushes The Display List Bits		( NEW )
	glListBase(base - 32);					// Sets The Base Character to 32	( NEW )

	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	// Draws The Display List Text	( NEW )
	glPopAttrib();						// Pops The Display List Bits	( NEW )
}




GLvoid ReSizeGLScene(GLsizei width, GLsizei height)				// Resize And Initialize The GL Window
{
	if (height==0)								// Prevent A Divide By Zero By
	{
		height=1;							// Making Height Equal One
	}

	glViewport(0, 0, width, height);					// Reset The Current Viewport
	
	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();							// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);						// Select The Modelview Matrix
	glLoadIdentity();							// Reset The Modelview Matrix
}



int InitGL(GLvoid)								// All Setup For OpenGL Goes Here
{
	glShadeModel(GL_SMOOTH);						// Enables Smooth Shading
	glClearColor(0.3f, 0.3f, 1.0f, 1.0f);			// Black Background

	glClearDepth(1.0f);								// Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);						// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);							// The Type Of Depth Test To Do

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Really Nice Perspective Calculations

	glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);				// Setup The Ambient Light
	glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);				// Setup The Diffuse Light
	glLightfv(GL_LIGHT0, GL_POSITION,LightPosition);			// Position The Light
	glEnable(GL_LIGHT0);							// Enable Light One
	glEnable(GL_LIGHTING);
	glEnable( GL_COLOR_MATERIAL );
	glEnable(GL_NORMALIZE);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.0f );

	BuildFont();						// Build The Font

	return TRUE;									// Initialization Went OK
}





int DrawGLScene(datas *d)//, graphicDatas *gd)//(datas *d, seaDatas *sd, boatDatas *bd)								// Here's Where We Do All The Drawing
{
	double sign;
	float X, Y, Z, R; //joystick axes

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear The Screen And The Depth Buffer
							

	if (abs((1.0f/time_elapsed))<300.0f) fps=0.99*fps+0.01*(1.0f/time_elapsed); //frames per second 

//On Screen Display informations (text and instruments):
	glLoadIdentity();

	glDisable(GL_LIGHTING);

	glTranslatef(0.0f,0.0f,-1.0f);	//translate for text display
	glColor3f(0.85,0.05,0.05);			//font color
	glRasterPos2f(-0.5, -0.35);		//font position
	glPrint("Speed %3.2f km/h    Course %3.0f deg", 
			3.6f*sqrt(d->dx*d->dx + d->dy*d->dy),
			-57.2958f*atan(d->dy/d->dx));	// Print GL Text To The Screen	
	glRasterPos2f(-0.5, -0.375);		//font position
	glPrint("Wind Speed %3.2f km/h,    %3.1f fps", 3.6f*d->Wind, fps);
	glRasterPos2f(-0.5, -0.4);		//font position
	glPrint("Relative Wind Speed %3.2f km/h", 3.6*sqrt((d->Wind_x - d->dx)*(d->Wind_x - d->dx)+(d->Wind_y - d->dy)*(d->Wind_y - d->dy)));

	glLoadIdentity();
	glTranslatef(-0.45f,0.4f,-1.0f);
	glScalef(0.08f,0.08f,0.08f);
	Girouette_draw(d);

	if (joystick_exist) 
	{
		joystick_getXYZR(&d->target_x, &d->target_y, &d->Vslider_x, &d->Hslider_x, doX, doY, doZ, doR);
		if (doX) d->target_x *= dirX;
		if (doY) d->target_y *= dirY;
		if (doZ) d->Vslider_x *= dirZ;
		if (doR) d->Hslider_x *= dirR;
	}

	angles_update(d); //update cal angles from target/sliders position

	glLoadIdentity();
	glTranslatef(0.48f,-0.35f,-1.0f);
	glScalef(0.05f,0.05f,0.04f);
	Target_draw(d->target_x, d->target_y); //draw target instrument

	glLoadIdentity();
	glTranslatef(0.35f,-0.35f,-1.0f);
	glScalef(0.1f,0.1f,0.1f);
	HSlider_draw(d->Hslider_x);  //draw horizontal slider instrument

	glLoadIdentity();
	glTranslatef(0.25f,-0.35f,-1.0f);
	glScalef(0.1f,0.1f,0.1f);
	VSlider_draw(d->Vslider_x);  //draw vertical slider instrument

	glEnable(GL_LIGHTING);

//3D graphics:
	glLoadIdentity();				//back to identity

	if (cos(viewAngle2) >= 0) sign=1.0; //avoid looking up-side-down when going over 90deg of vertical view angle
	else sign=-1.0;

	gluLookAt(    d->x - cos(viewAngle1)*cos(viewAngle2)*viewDist,   //look at boat
				  d->y + sin(viewAngle1)*cos(viewAngle2)*viewDist,
				  d->z + sin(viewAngle2)*viewDist, 

				  d->x,d->y,d->z+12.0,

				  sin(viewAngle2)*cos(viewAngle1) * sign,
				  -sin(viewAngle2)*sin(viewAngle1) * sign,
				  cos(viewAngle2) * sign); 

	glTranslatef(d->x,d->y,0.0);

	wave_z_compute(d);//, gd);
	Draw_sea();//gd);

	glTranslatef(0.0,0.0,d->z);
	glRotatef(57.2958*d->phi,1.0f,0.0f,0.0f);
	glRotatef(57.2958*d->theta,0.0f,1.0f,0.0f);
	glRotatef(57.2958*d->psi,0.0f,0.0f,1.0f);

	Boat_draw();
	Sail_create_and_draw(d);
	RelativeWind_draw(d);

	glLightfv(GL_LIGHT0, GL_POSITION,LightPosition); //?ici?


	return TRUE;								// Everything Went OK
}




GLvoid KillGLWindow(GLvoid)							// Properly Kill The Window
{
	if (fullscreen)								// Are We In Fullscreen Mode?
	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		ShowCursor(TRUE);						// Show Mouse Pointer
	}

	if (hRC)								// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))					// Are We Able To Delete The RC?
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;							// Set RC To NULL
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;							// Set DC To NULL
	}

	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;							// Set hWnd To NULL
	}

	if (!UnregisterClass("OpenGL",hInstance))				// Are We Able To Unregister Class
	{
		MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;							// Set hInstance To NULL
	}
}




BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;						// Holds The Results After Searching For A Match

	WNDCLASS	wc;							// Windows Class Structure

	DWORD		dwExStyle;						// Window Extended Style
	DWORD		dwStyle;						// Window Style

	RECT WindowRect;							// Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left=(long)0;						// Set Left Value To 0
	WindowRect.right=(long)width;						// Set Right Value To Requested Width
	WindowRect.top=(long)0;							// Set Top Value To 0
	WindowRect.bottom=(long)height;						// Set Bottom Value To Requested Height

	fullscreen=fullscreenflag;						// Set The Global Fullscreen Flag

	hInstance		= GetModuleHandle(NULL);			// Grab An Instance For Our Window
	wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// Redraw On Move, And Own DC For Window
	wc.lpfnWndProc		= (WNDPROC) WndProc;				// WndProc Handles Messages
	wc.cbClsExtra		= 0;						// No Extra Window Data
	wc.cbWndExtra		= 0;						// No Extra Window Data
	wc.hInstance		= hInstance;					// Set The Instance
	wc.hIcon		= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;						// No Background Required For GL
	wc.lpszMenuName		= NULL;						// We Don't Want A Menu
	wc.lpszClassName	= "OpenGL";					// Set The Class Name

	if (!RegisterClass(&wc))						// Attempt To Register The Window Class
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Exit And Return FALSE
	}

	if (fullscreen)								// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;					// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));		// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;			// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;			// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;				// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Run In A Window.
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;				// Select Windowed Mode (Fullscreen=FALSE)
			}
			else
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;					// Exit And Return FALSE
			}
		}
	}

	if (fullscreen)								// Are We Still In Fullscreen Mode?
	{
		dwExStyle=WS_EX_APPWINDOW;					// Window Extended Style
		dwStyle=WS_POPUP;						// Windows Style
		ShowCursor(FALSE);						// Hide Mouse Pointer
	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle=WS_OVERLAPPEDWINDOW;					// Windows Style
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size

	if (!(hWnd=CreateWindowEx(	dwExStyle,				// Extended Style For The Window
					"OpenGL",				// Class Name
					title,					// Window Title
					WS_CLIPSIBLINGS |			// Required Window Style
					WS_CLIPCHILDREN |			// Required Window Style
					dwStyle,				// Selected Window Style
					0, 0,					// Window Position
					WindowRect.right-WindowRect.left,	// Calculate Adjusted Window Width
					WindowRect.bottom-WindowRect.top,	// Calculate Adjusted Window Height
					NULL,					// No Parent Window
					NULL,					// No Menu
					hInstance,				// Instance
					NULL)))					// Don't Pass Anything To WM_CREATE
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	static	PIXELFORMATDESCRIPTOR pfd=					// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),					// Size Of This Pixel Format Descriptor
		1,								// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,						// Must Support Double Buffering
		PFD_TYPE_RGBA,							// Request An RGBA Format
		bits,								// Select Our Color Depth
		0, 0, 0, 0, 0, 0,						// Color Bits Ignored
		0,								// No Alpha Buffer
		0,								// Shift Bit Ignored
		0,								// No Accumulation Buffer
		0, 0, 0, 0,							// Accumulation Bits Ignored
		16,								// 16Bit Z-Buffer (Depth Buffer)
		0,								// No Stencil Buffer
		0,								// No Auxiliary Buffer
		PFD_MAIN_PLANE,							// Main Drawing Layer
		0,								// Reserved
		0, 0, 0								// Layer Masks Ignored
	};


	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))				// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	if(!SetPixelFormat(hDC,PixelFormat,&pfd))				// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	if (!(hRC=wglCreateContext(hDC)))					// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	if(!wglMakeCurrent(hDC,hRC))						// Try To Activate The Rendering Context
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	ShowWindow(hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(hWnd);						// Slightly Higher Priority
	SetFocus(hWnd);								// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);						// Set Up Our Perspective GL Screen


	if (!InitGL())								// Initialize Our Newly Created GL Window
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}


	return TRUE;								// Success
}



/// Callback and keyboard management
LRESULT CALLBACK WndProc(	HWND	hWnd,					// Handle For This Window
				UINT	uMsg,					// Message For This Window
				WPARAM	wParam,					// Additional Message Information
				LPARAM	lParam)					// Additional Message Information
{
	switch (uMsg)								// Check For Windows Messages
	{
		case WM_ACTIVATE:						// Watch For Window Activate Message
		{
			if (!HIWORD(wParam))					// Check Minimization State
			{
				active=TRUE;					// Program Is Active
			}
			else
			{
				active=FALSE;					// Program Is No Longer Active
			}

			return 0;						// Return To The Message Loop
		}
		case WM_SYSCOMMAND:						// Intercept System Commands
		{
			switch (wParam)						// Check System Calls
			{
				case SC_SCREENSAVE:				// Screensaver Trying To Start?
				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
				return 0;					// Prevent From Happening
			}
			break;							// Exit
		}
		case WM_CLOSE:							// Did We Receive A Close Message?
		{
			PostQuitMessage(0);					// Send A Quit Message
			return 0;						// Jump Back
		}
		case WM_KEYDOWN:						// Is A Key Being Held Down?
		{
			keys[wParam] = TRUE;					// If So, Mark It As TRUE
			return 0;						// Jump Back
		}
		case WM_KEYUP:							// Has A Key Been Released?
		{
			keys[wParam] = FALSE;					// If So, Mark It As FALSE
			return 0;						// Jump Back
		}
		case WM_SIZE:							// Resize The OpenGL Window
		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));		// LoWord=Width, HiWord=Height
			return 0;						// Jump Back
		}
	}

	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}



int draw_graphics_init(datas *d)//, graphicDatas *gd)
{

	// Ask The User Which Screen Mode They Prefer
	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
		fullscreen=FALSE;						// Windowed Mode
	}

	// Create Our OpenGL Window
	if (!CreateGLWindow("Hydroptere",640,480,16,fullscreen))
	{
		return 0;							// Quit If Window Was Not Created
	}


	//joystick:
	if (joystick_init()!=1)
	{
		printf("Can't initialize joystick");
		joystick_exist = 0;
	}
	else
	{
		joystick_exist = 1;
	}

	return 1; //OK...
}


bool draw_graphics(datas *d)//, graphicDatas *gd)
{
	float tempAngle;

	if(!done)								// Loop That Runs Until done=TRUE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))			// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;					// If So done=TRUE
			}
			else							// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		else								// If There Are No Messages
		{
			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
			if (active)						// Program Active?
			{
				if (keys[VK_ESCAPE])				// Was ESC Pressed?
				{
					done=TRUE;				// ESC Signalled A Quit
				}
				else						// Not Time To Quit, Update Screen
				{
					//DrawGLScene(d, sd, bd);				// Draw The Scene
					DrawGLScene(d);//,gd);
					SwapBuffers(hDC);			// Swap Buffers (Double Buffering)
				}
			}
			if (keys[VK_F1])					// Is F1 Being Pressed?
			{
				keys[VK_F1]=FALSE;				// If So Make Key FALSE
				KillGLWindow();					// Kill Our Current Window
				fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode
				// Recreate Our OpenGL Window
				if (!CreateGLWindow("Hydroptere",640,480,16,fullscreen))
				{
					return FALSE;				// Quit If Window Was Not Created
				}
			}
		}
	}
	//Change viewpoint from keyboard:
	if (keys['Q'])
	{
		viewAngle1 += dviewAngle;
	}
	if (keys['W'])
	{
		viewAngle1 -= dviewAngle;
	}
	if (keys['E'])
	{
		viewAngle2 += dviewAngle;
	}
	if (keys['R'])
	{
		viewAngle2 -= dviewAngle;
	}
	if (keys['T'])
	{
		viewDist += dviewDist;
	}
	if (keys['Z'])
	{
		viewDist -= dviewDist;
	}
	//Joystick directions changes:
	if (keys['X'] && allowChangeDirX) {dirX*=-1.0f; allowChangeDirX = FALSE;}
	else if (!keys['X']) allowChangeDirX = TRUE;

	if (keys['Y'] && allowChangeDirY) {dirY*=-1.0f; allowChangeDirY = FALSE;}
	else if (!keys['Y']) allowChangeDirY = TRUE;

	if (keys['V'] && allowChangeDirZ) {dirZ*=-1.0f; allowChangeDirZ = FALSE;}
	else if (!keys['V']) allowChangeDirZ = TRUE;

	if (keys['C'] && allowChangeDirR) {dirR*=-1.0f; allowChangeDirR = FALSE;}
	else if (!keys['C']) allowChangeDirR = TRUE;

	//use keyboard or joystick for each axes
	if (keys['1'] && allowChangeDoX) {doX=!doX; allowChangeDoX = FALSE;}
	else if (!keys['1']) allowChangeDoX = TRUE;

	if (keys['2'] && allowChangeDoY) {doY=!doY; allowChangeDoY = FALSE;}
	else if (!keys['2']) allowChangeDoY = TRUE;

	if (keys['3'] && allowChangeDoZ) {doZ=!doZ; allowChangeDoZ = FALSE;}
	else if (!keys['3']) allowChangeDoZ = TRUE;

	if (keys['4'] && allowChangeDoR) {doR=!doR; allowChangeDoR = FALSE;}
	else if (!keys['4']) allowChangeDoR = TRUE;


	//keyboard controll:
	time_elapsed = d->t - time_before;

	if (keys[VK_UP]		&&	d->target_y<1.0f)	 d->target_y += 1.5f*time_elapsed;
	if (keys[VK_DOWN]	&&	d->target_y>-1.0f) d->target_y -= 1.5f*time_elapsed;

	if (keys[VK_RIGHT]	&&	d->target_x<1.0f) d->target_x += 1.5f*time_elapsed;
	if (keys[VK_LEFT]	&&	d->target_x>-1.0f) d->target_x -= 1.5f*time_elapsed;

	if (keys['M']	&&	d->Hslider_x<1.0f) d->Hslider_x += 1.5f*time_elapsed;
	if (keys['N']	&&	d->Hslider_x>-1.0f) d->Hslider_x -= 1.5f*time_elapsed;

	if (keys['H']	&&	d->Vslider_x<1.0f) d->Vslider_x += 1.5f*time_elapsed;
	if (keys['B']	&&	d->Vslider_x>-1.0f) d->Vslider_x -= 1.5f*time_elapsed;

	if (keys[VK_SPACE]) {d->target_x=0.0f; d->target_y=0.0; d->Hslider_x=0.0f; d->Vslider_x=0.0f;} //recenter all commands

	//sail:
	if (keys['K'] && d->max_abs_angle_baume<1.4835f) { //max 85 degree
		d->max_abs_angle_baume += 0.1745*time_elapsed; // 10 degrees/second
	}
	if (keys['L'] && d->max_abs_angle_baume>0.0f) { //min 0.0 degree
		d->max_abs_angle_baume -= 0.1745*time_elapsed; // 10 degrees/second
	}
	//Sail goes with the wind and is constrained by +- d->max_abs_angle_baume:
	d->tanAngle_sail = tan(d->angle_girouette);
	if (atan(d->tanAngle_sail)>d->max_abs_angle_baume) d->tanAngle_sail=tan(d->max_abs_angle_baume);
	if (atan(d->tanAngle_sail)< -d->max_abs_angle_baume) d->tanAngle_sail=tan(-d->max_abs_angle_baume);
/*	if (keys['K'] && atan(d->tanAngle_sail)<1.4835f) { //max 85 degree
		tempAngle = atan(d->tanAngle_sail);
		tempAngle += 0.1745*time_elapsed; // 10 degrees/second
		d->tanAngle_sail = tan(tempAngle);
	}
	if (keys['L'] && atan(d->tanAngle_sail)>-1.4835f) { //min -85 degree
		tempAngle = atan(d->tanAngle_sail);
		tempAngle -= 0.1745*time_elapsed; // 10 degrees/second
		d->tanAngle_sail = tan(tempAngle);
	}
*/

	//Wind:
	if (keys['9']){ //more wind
		d->Wind += 2.0f*time_elapsed;
		d->Wind_x = -d->Wind*cos(d->Wind_angle);
		d->Wind_y = -d->Wind*sin(d->Wind_angle);
	}
	if (keys['8'] && d->Wind>0){ //less wind
		d->Wind -= 2.0f*time_elapsed;
		d->Wind_x = -d->Wind*cos(d->Wind_angle);
		d->Wind_y = -d->Wind*sin(d->Wind_angle);
	}

	//Wave amplitude:
	if (keys['7']) {
		d->Wave_amp0 += 0.15f*time_elapsed;
		d->Wave_amp[0] = d->Wave_amp0/2.0;
		d->Wave_amp[1] = d->Wave_amp0/4.0;
		d->Wave_amp1 = d->Wave_amp[0];
		d->Wave_amp2 = d->Wave_amp[1];
	}
	if (keys['6'] && d->Wave_amp0>0.0f) {
		d->Wave_amp0 -= 0.15f*time_elapsed;
		d->Wave_amp[0] = d->Wave_amp0/2.0;
		d->Wave_amp[1] = d->Wave_amp0/4.0;
		d->Wave_amp1 = d->Wave_amp[0];
		d->Wave_amp2 = d->Wave_amp[1];
	}


	time_before = d->t;


	return (!done);
}


int draw_graphics_kill()
{
	// Shutdown
	KillGLWindow();								// Kill The Window
	done=FALSE; //so that windows do not close imediatelly if MEX is relaunched in same MATLAB session

	joystick_close();

	return (msg.wParam);							// Exit The Program
}




void pass_joy_parameters(joy_parameters *jP) //pass parameters here (comming from MATLAB)
{
	doX = jP->doX;
	doY = jP->doY;
	doZ = jP->doZ;
	doR = jP->doR;

	dirX = jP->dirX;
	dirY = jP->dirY;
	dirZ = jP->dirZ;
	dirR = jP->dirR;
}