// start.cpp : Defines the entry point for the application.
//

#pragma comment(lib, "ode.lib")
#pragma comment(lib, "OPENGL32.LIB")
#pragma comment(lib, "GLU32.LIB")
//#pragma comment(lib, "glut32.lib")
//#pragma comment(lib, "GLAUX.LIB")
//#pragma comment(lib, "WinMM.Lib") //sound

#include "stdafx.h"

#include <windows.h>		// Header File For Windows
#include <math.h>			// Header File For Windows Math Library
#include <stdio.h>			// Header File For Standard Input/Output
#include <stdarg.h>			// Header File For Variable Argument Routines
#include <ctime>    // For time()
#include <cstdlib>  // For srand() and rand()
#include <Mmsystem.h>//sound


#include <gl\gl.h>			// Header File For The OpenGL32 Library
#include <gl\glu.h>			// Header File For The GLu32 Library
//#include <gl\glaux.h>		// Header File For The Glaux Library
//#include <gl\glut.h>		// Header File For The Glaux Library

#include <olectl.h>														// Header File For The OLE Controls Library	(Used In BuildTexture)
#include <math.h>														// Header File For The Math Library			(Used In BuildTexture)

#include <ode\ode.h>

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

int cnt3;
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


#define PI (3.141592654f)
#define DEGTORAD(degree) ((PI / 180.0f) * (degree))
#define RADTODEG(radian) ((180.0f /PI) * (radian))


LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc
void WriteConfig(HWND hwnd);
void GetConfig();
int bitsPP=16;
int screenWidth=640;
int screenHeight=480;
int dFps=30;
float sGravity=-10.5f;
float boxMass=0.02f;

char AppPath[_MAX_PATH];
char filename[_MAX_PATH];
char tempStr[_MAX_PATH];

#define Mouse_Thresold 44
int mouse_move_count=1,curx,cury;
bool pMode;

//FPS
	static float fps           = 0.0f;						
    static float previousTime  = 0.0f;	
	static char  strFPS[20]    = {0};
	float sleepTime=0;
	float fpsDesired=(float) dFps;
	float fpsNow;

///////////////////////////////
//ODE

#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCappedCylinder dsDrawCappedCylinderD
#endif

// some constants
#define LENGTH 0.7	// chassis length
#define WIDTH 0.5	// chassis width

#define HEIGHT 0.2	// chassis height
#define RADIUS 0.18	// wheel radius
#define STARTZ 0.5	// starting height of chassis
#define CMASS 1		// chassis mass
#define WMASS 0.2	// wheel mass
#define MAX_CONTACTS 8		// maximum number of contact points per body
#define nCars 3
#define nFloors 2
// dynamics and collision objects (chassis, 3 wheels, environment)
struct MyObject {
  dBodyID body;			// the body
  dGeomID geom;		// geometries representing this body
};
struct bBoard {
	dGeomID geom;		// geometries representing this body
	float width;
	float height;
};
#define RANDF	((float)rand()/RAND_MAX)
#define nPillars 50
int lPillar =1;

#define nPc 5
bool isactive=false;

float stepSz =0.05f;

static dWorldID world;
static dSpaceID space;
static dBodyID body[5];
static dJointID joint[4];	// joint[0] is the front wheel
static dJointGroupID contactgroup;
static dGeomID ground;
static dSpaceID car_space[nCars];
static dGeomID box[2]; // box[0] is car
static dGeomID sphere[4];
static dGeomID wall[6];// sides and top
static bBoard miBB[10];
static MyObject miBox[nPillars];
static MyObject miChair, mySphere[4];
static MyObject miPc[5];
static dGeomID ground_box;

int cntBox=0;
int i;float vx,vy,vz,zforce=0,zinc=0.01; // zforce=engine force up
// things that the user controls

static dReal speed[nCars],steer[nCars];	// user commands
static double cangle=0, celev=1, cdist = 4; 
float cmov=0.01f;  //Camera speed.
float cTheta=50; //Degree of 360.
int camera=1, maxcam=5;
float camx=1000,camy=0;

//Car Var and struct
struct MyCar 
{
	dJointID hChasisRoofFront,hChasisRoofBack,hWheelRBChasis,hWheelLBChasis;
	dJointID hChasisExcelL,hChasisExcelR,hexcelJoinExcelL,hexcelJoinExcelR,hRightWheelExcel,hLeftWheelExcel;
	MyObject wheelRR,wheelRL,CarChasis,wheelFL,excelL,excelR,wheelFR,excelJoin,carTop;
	
	int colR,colG,colB;
	bool autoPilotOn,goahead;
	int carState,Sensing,BubbleCount; float BubbleTime;
	int PFpathLength,PFpathLoc,PFpathX[9999],PFpathY[9999];
	int TeamNo, Health, Alive, Energy, EnemyID, Mood; //Mood 0=roam,1=chase,2=evade,3=getfuel,4=gethealth

}	PcCar[nCars];

struct MyFloor
{
	dJointID hFloorRamp;
	MyObject Pillar1,Pillar2,Pillar3,Pillar4,Roof,Ramp;
	
}	Floors[nFloors];

///////////////////////////////
//Text 
GLuint	texture[10];			// Storage For One Texture ( NEW )
GLuint	boxtex[100];			// Storage For One Texture ( NEW )

GLfloat	xrot;				// X Rotation ( NEW )
GLfloat	yrot;				// Y Rotation ( NEW )
GLfloat	zrot;				// Z Rotation ( NEW )
bool textOn=0;
///////////////////////////////
//GL 

GLuint	base;				// Base Display List For The Font Set
GLfloat	cnt1;				// 1st Counter Used To Move Text & For Coloring
GLfloat	cnt2;				// 2nd Counter Used To Move Text & For Coloring
float camerax=-4, cameray=-4;
#include "mifont.h"
#include "miode.h"
#include "midraw.h"
#include "mitex.h"
#include "miogl.h"
#include "resource.h"

void energize()//the pillars!
{
	srand(time(0));  // Initialize random number generator.
	for (i=0;i<nPillars;i++)
	{
		dBodyEnable (miBox[i].body);
		vx = ((rand() % 30) + 1)-15; vx=vx/10;vy = (((rand() % 30) + 1)-15)/10; vz = (((rand() % 30) + 1)-15)/10;
		dBodySetLinearVel (miBox[i].body, vx, vy, vz);// E - velociti
	}
}

///////////////////////////////

void FPS()					// This function calculates FPS
{
	float currentTime = (GetTickCount() * 0.001f);				

    ++fps;	// Increment the FPS counter

    if( currentTime - previousTime > 10.0f )
    {
	    previousTime = currentTime;
		fpsNow=fps/10;
		sprintf(strFPS, "FPS: %.1f", fpsNow);
		SetWindowText(hWnd, strFPS);
        fps = 0.0f;
		
		lPillar++;if (lPillar==nPillars)lPillar=1;
		//energize();//kick the boxes
		if (fpsNow<fpsDesired-10)sleepTime-=10;if(sleepTime<0)sleepTime=0;
		if (fpsNow>fpsDesired+10)sleepTime+=10;
    }

	//Sleep(sleepTime); disabled
}

//***********************************************************************

void KeyHandling()
{

	if(keys[VK_LEFT])
	{
		if (steer[0]<.5)steer[0] += 0.001;
	}
	else if(keys[VK_RIGHT])
	{
		if (steer[0]>-.5)steer[0] -= 0.001;
	}
	else
	{
		steer[0] = 0.0;
	}

	if(!keys[VK_UP])if (speed[0]>0)speed[0]=0;
	if(!keys[VK_DOWN])if (speed[0]<0)speed[0]=0;
	if(keys[VK_UP])   if (speed[0]<1000) speed[0] += 5;
	if(keys[VK_DOWN]) if (speed[0]>-1000)  speed[0] -= 5;

	if(keys[VK_SPACE]) {
		speed[0] = 0;
		steer[0] = 0;
	}

	if(keys[77]) dBodyAddForce(PcCar[0].carTop.body, 0.0, 0.0, 25); // M

	/////////////////////////////
	//Car 2

	if(keys[65]) //A
	{
		if (steer[1]<.5)steer[1] += 0.001;
	}
	else if(keys[68]) //D
	{
		if (steer[1]>-.5)steer[1] -= 0.001;
	}
	else
	{
		steer[1] = 0.0;
	}

	if(!keys[87])if (speed[1]>0)speed[1]=0; //W
	if(!keys[83])if (speed[1]<0)speed[1]=0; //S
	if(keys[87])   if (speed[1]<1000) speed[1] += 5;
	if(keys[83]) if (speed[1]>-1000)  speed[1] -= 5;
	if(keys[81]) dBodyAddForce(PcCar[1].carTop.body, 0.0, 0.0, 25); // Q - up force

	/////////////////////////////
	//Car 3

	if(keys[74]) //J
	{
		if (steer[2]<0.5)steer[2] += 0.001;
	}
	else if(keys[76]) //L
	{
		if (steer[2]>-0.5)steer[2] -= 0.001;
	}
	else
	{
		steer[2] = 0.0;
	}

	if(!keys[73])if (speed[2]>0)speed[2]=0; //I
	if(!keys[75])if (speed[2]<0)speed[2]=0; //K
	if(keys[73]) if (speed[2]<1000) speed[2] += 5;
	if(keys[75]) if (speed[2]>-1000)  speed[2] -= 5;
	if(keys[85]) dBodyAddForce(PcCar[2].carTop.body, 0.0, 0.0, 25); // U - up force
}

//***********************************************************************

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
{
	static POINT pt;
	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
			//PostQuitMessage(0);
			if ((wParam==67) || (wParam==99)) {camera++; if (camera>maxcam)camera=1;}
			
			if (wParam==VK_SPACE)//break on front
			{
				dJointSetHingeParam(PcCar[0].hLeftWheelExcel, dParamVel,  5); 
				dJointSetHingeParam(PcCar[0].hLeftWheelExcel, dParamFMax, 5);
				dJointSetHingeParam(PcCar[0].hRightWheelExcel, dParamVel,  5); 
				dJointSetHingeParam(PcCar[0].hRightWheelExcel, dParamFMax, 5);
			}

			return 0;								// Jump Back
		}

		case WM_KEYUP:								// Has A Key Been Released?
		{
			if (wParam==VK_SPACE)//brake off front
			{
				dJointSetHingeParam(PcCar[0].hLeftWheelExcel, dParamVel,  5); 
				dJointSetHingeParam(PcCar[0].hLeftWheelExcel, dParamFMax, 0);
				dJointSetHingeParam(PcCar[0].hRightWheelExcel, dParamVel,  5); 
				dJointSetHingeParam(PcCar[0].hRightWheelExcel, dParamFMax, 0);
			}

			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
		}
		case WM_MOUSEMOVE:
		{
			if(mouse_move_count==1)
			{
				GetCursorPos(&pt);
				curx=pt.x;
				cury=pt.y;
			}
			else
			{
  				int dx,dy;
				GetCursorPos(&pt);			   
				dx=pt.x-curx;
				dy=pt.y-cury;

				if(dx<0)
					dx=dx*-1;
				if(dy<0)
					dy=dy*-1;

				if(dx>Mouse_Thresold|dy>Mouse_Thresold)
				{
					mouse_move_count=0;
					KillFont();
					if(!pMode)PostQuitMessage(0);
				}
			}
			mouse_move_count++;
			return 0;
		}
	}

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

//***********************************************************************

BOOL CALLBACK DialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
	case WM_INITDIALOG:
		GetConfig();
		SetDlgItemInt(hDlg, IDC_EDIT1, bitsPP, FALSE);
		SetDlgItemInt(hDlg, IDC_EDIT2, screenWidth, FALSE);
		SetDlgItemInt(hDlg, IDC_EDIT3, screenHeight, FALSE);
		SetDlgItemInt(hDlg, IDC_EDIT4, dFps, FALSE);
		
		sprintf(tempStr, "%.5f", sGravity);
		SetDlgItemText(hDlg, IDC_EDIT5, tempStr);
		sprintf(tempStr, "%.5f", boxMass);
		SetDlgItemText(hDlg, IDC_EDIT6, tempStr);

		return(TRUE);		
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			case IDOK:
				EndDialog(hDlg,0);
				WriteConfig(hDlg);
				PostQuitMessage(0);	
			break;
			case IDCANCEL:
				EndDialog(hDlg,0);
				PostQuitMessage(0);	
			break;
		}
		break;
	}
	return(FALSE);
}

//***********************************************************************

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{	
	if(hPrevInstance)return 0;
	MSG		msg;									// Windows Message Structure
	BOOL	done=FALSE;			// Bool Variable To Exit Loop
	BOOL    glOn=FALSE;
	//if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	//{
		fullscreen=FALSE;							// Windowed Mode
	//}

GetModuleFileName(NULL, filename, _MAX_PATH);

strcpy (AppPath,filename);
char* pch;
pch=strrchr(AppPath,'\\');
strncpy (pch,"\0",1);
strcat(AppPath,"\\");
pMode=false;
//MessageBox(NULL,filename,"",0);
//MessageBox(NULL,AppPath,"",0);
//sprintf(strFPS, "[%s]", lpCmdLine);
//MessageBox(NULL,strFPS,"lpCmdLine!",0);

	if((lpCmdLine[1]=='p')||(lpCmdLine[1]=='P'))//Saver preview.
	{
		while((*lpCmdLine)!=' ') lpCmdLine++;
		HWND hPwnd=(HWND)atoi(lpCmdLine);//Windows preview window Handle.
		RECT rc;int scx,scy;
		GetClientRect(hPwnd,&rc);
		scx=rc.right-rc.left;
		scy=rc.bottom-rc.top;

		fullscreen=FALSE;
		if (!CreateGLWindow("Energize",scx,scy,32,fullscreen,WS_CHILD,hPwnd))return 0;
		glOn=TRUE;
		pMode=TRUE;
	}
	else if((lpCmdLine[1]=='s')||(lpCmdLine[1]=='S')) //lpCmdLine[1]=='S'
	{
		fullscreen=TRUE;
		//fullscreen=FALSE; //TESTING
		GetConfig();
		fpsDesired=dFps;
//		if(!CreateGLWindow("Start",640,480,32,fullscreen,WS_OVERLAPPEDWINDOW,NULL))return 0;
		if(!CreateGLWindow("Start",screenWidth,screenHeight,bitsPP,fullscreen,WS_OVERLAPPEDWINDOW,NULL))return 0;
		glOn=TRUE;
	}
	else if((lpCmdLine[1]=='c')||(lpCmdLine[1]=='C'))//Config Dialog.
	{
		DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);
	}
	else
	{
		DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);
	}

		if (glOn){
			initOde();
			BuildFont();
		}

		//****************
		while(!done)									// Loop That Runs While done=FALSE
		{
			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
			{
				// Handle Keys
				KeyHandling();
				FPS();
				simLoop(0);
				// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
				if ((active && !DrawGLScene()) || keys[VK_ESCAPE])	// Active?  Was There A Quit Received?
				{
					done=TRUE;							// ESC or DrawGLScene Signalled A Quit
				}
				else									// Not Time To Quit, Update Screen
				{
					SwapBuffers(hDC);					// Swap Buffers (Double Buffering)
				}
			}
		}

		if (glOn){
			KillGLWindow();									// Kill The Window
			endOde();
			KillFont();
		}


	return (msg.wParam);							// Exit The Program
}
//******************************************************************************
/////////   REGISTRY ACCESS FUNCTIONS     ///////////


BOOL bSuccess;

void GetConfig()
{
	HKEY key;
	//DWORD lpdw;

	if (RegOpenKeyEx( HKEY_CURRENT_USER,
		"Software\\ScreenSaverEnergize", //lpctstr
		0,			//reserved
		KEY_QUERY_VALUE,
		&key) == ERROR_SUCCESS)	
	{
		DWORD dsize = sizeof(bitsPP);
		DWORD dwtype =  0;

		RegQueryValueEx(key,"bitsPP", NULL, &dwtype, (BYTE*)&bitsPP, &dsize);
		RegQueryValueEx(key,"screenWidth", NULL, &dwtype, (BYTE*)&screenWidth, &dsize);
		RegQueryValueEx(key,"screenHeight", NULL, &dwtype, (BYTE*)&screenHeight, &dsize);
		RegQueryValueEx(key,"dFps", NULL, &dwtype, (BYTE*)&dFps, &dsize);
		
		int temp;
		RegQueryValueEx(key,"sGravity", NULL, &dwtype, (BYTE*)&temp, &dsize);
		sGravity=temp/100000;//convert to float
		RegQueryValueEx(key,"boxMass", NULL, &dwtype, (BYTE*)&temp, &dsize);
		boxMass=temp/100000;//convert to float

		RegCloseKey(key);
	}
	else //key isn't there yet--set defaults
	{
		//no need
	}
}

void WriteConfig(HWND hwnd)
{   
	bitsPP=GetDlgItemInt(hwnd, IDC_EDIT1, &bSuccess, FALSE);
	screenWidth=GetDlgItemInt(hwnd, IDC_EDIT2, &bSuccess, FALSE);
	screenHeight=GetDlgItemInt(hwnd, IDC_EDIT3, &bSuccess, FALSE);
	dFps=GetDlgItemInt(hwnd, IDC_EDIT4, &bSuccess, FALSE);

	GetDlgItemText(hwnd, IDC_EDIT5,tempStr,255);
	sGravity=atof(tempStr);
	GetDlgItemText(hwnd, IDC_EDIT6,tempStr,255);
	boxMass=atof(tempStr);

	
	HKEY key;
	DWORD lpdw;

	if (RegCreateKeyEx( HKEY_CURRENT_USER,
		"Software\\ScreenSaverEnergize", //lpctstr
		0,			//reserved
		"",			//ptr to null-term string specifying the object type of this key
		REG_OPTION_NON_VOLATILE,
		KEY_WRITE,
		NULL,
		&key,
		&lpdw) == ERROR_SUCCESS)
	{
		RegSetValueEx(key,"bitsPP", 0, REG_DWORD, (BYTE*)&bitsPP, sizeof(bitsPP));
		RegSetValueEx(key,"screenWidth", 0, REG_DWORD, (BYTE*)&screenWidth, sizeof(screenWidth));
		RegSetValueEx(key,"screenHeight", 0, REG_DWORD, (BYTE*)&screenHeight, sizeof(screenHeight));
		RegSetValueEx(key,"dFps", 0, REG_DWORD, (BYTE*)&dFps, sizeof(dFps));
		
		int temp=sGravity*100000;//storing float data;
		RegSetValueEx(key,"sGravity", 0, REG_DWORD, (BYTE*)&temp, sizeof(temp));
		temp=boxMass*100000;
		RegSetValueEx(key,"boxMass", 0, REG_DWORD, (BYTE*)&temp, sizeof(temp));

		//Finished with keys
		RegCloseKey(key);
	}
}