#include"main.h"

#define MAX_ANGLE	75
#define MAX_SCALE	-2.5
#define MIN_SCALE	-20
#define MAX_TEXTURES 4

GLuint texture[MAX_TEXTURES];
GLfloat g_fScale = -5;
GLint g_nYaw = 0;
GLint g_nPitch = 0;
GLint g_nMaxTex = (MAX_TEXTURES-1);
GLint g_nLeftTex = 0;
GLint g_nRightTex = 0;
GLint g_nMaxAnisotropy = 0;

void ApplicationCallback(void)
{
	return;
}

BOOL LoadTexture(void)
{
	AUX_RGBImageRec	*pTexture;
	GLint nTexSize;

	glGetIntegerv(GL_MAX_TEXTURE_SIZE,&nTexSize);
	LogMsg("MAX Texture side size for this card: %d\n",nTexSize);

	if ((pTexture = auxDIBImageLoad("texture.bmp")) == NULL)
	{
		return FALSE;
	}

	if (pTexture->data == NULL)
	{
		free(pTexture);
		return FALSE;
	}

	glGenTextures(MAX_TEXTURES,texture);

	glBindTexture(GL_TEXTURE_2D,texture[0]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexImage2D(GL_TEXTURE_2D,0,3,pTexture->sizeX,pTexture->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,pTexture->data);

	glBindTexture(GL_TEXTURE_2D,texture[1]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	gluBuild2DMipmaps(GL_TEXTURE_2D,3,pTexture->sizeX,pTexture->sizeY,GL_RGB,GL_UNSIGNED_BYTE,pTexture->data);

	glBindTexture(GL_TEXTURE_2D,texture[2]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
	gluBuild2DMipmaps(GL_TEXTURE_2D,3,pTexture->sizeX,pTexture->sizeY,GL_RGB,GL_UNSIGNED_BYTE,pTexture->data);

	if (g_nMaxTex == (MAX_TEXTURES-1))
	{
		LogMsg("Using anisotropy level: %f\n",(float)(g_nMaxAnisotropy-0.1));
		glBindTexture(GL_TEXTURE_2D,texture[3]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,g_nMaxAnisotropy-0.1);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
		gluBuild2DMipmaps(GL_TEXTURE_2D,3,pTexture->sizeX,pTexture->sizeY,GL_RGB,GL_UNSIGNED_BYTE,pTexture->data);
	}

	free(pTexture->data);
	free(pTexture);

	return TRUE;
}

void DrawWall(void)
{
	glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 1.0f);glVertex3f(-1.0f, 1.0f, 0.0f);					
		glTexCoord2f(1.0f, 1.0f);glVertex3f( 1.0f, 1.0f, 0.0f);					
   		glTexCoord2f(1.0f, 0.0f);glVertex3f( 1.0f,-1.0f, 0.0f);					
		glTexCoord2f(0.0f, 0.0f);glVertex3f(-1.0f,-1.0f, 0.0f);					
	glEnd();											

	return;
}

void DrawScreen(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	

	glLoadIdentity();									
	glTranslatef(-1.1f,0.0f,g_fScale);

	glRotatef(g_nPitch,1.0f,0.0f,0.0f);						
	glRotatef(g_nYaw,0.0f,1.0f,0.0f);						
	glBindTexture(GL_TEXTURE_2D,texture[g_nLeftTex]);

	DrawWall();

	glLoadIdentity();									
	glTranslatef(1.1,0.0,g_fScale);

	glRotatef(g_nPitch,1.0f,0.0f,0.0f);						
	glRotatef(g_nYaw,0.0f,1.0f,0.0f);						
	glBindTexture(GL_TEXTURE_2D,texture[g_nRightTex]);

	DrawWall();
	
	glFinish();
	SwapBuffers(g_hDc);

	return;
}

void ApplicationPreinit(void)
{
	char *pszExtStr = (char *)glGetString(GL_EXTENSIONS);

	LogMsg("Supported extensions: %s\n",pszExtStr);

	if (!IsInString(pszExtStr,"GL_EXT_texture_filter_anisotropic"))
	{
		MessageBox(NULL,"\nAnisotropic texture filtering not found !","Skipping filtering...",MB_OK | MB_ICONINFORMATION);
		LogMsg("GL_EXT_texture_filter_anisotropic not found !\n");
		g_nMaxTex--;
	}
	else
	{                 
		glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&g_nMaxAnisotropy);
		LogMsg("MAX anisotropy: %d\n",g_nMaxAnisotropy);
	}

	glViewport(0,0,g_nAppPar[APP_WIDTH],g_nAppPar[APP_HEIGHT]);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();								

	gluPerspective(45.0f,(GLfloat)g_nAppPar[APP_WIDTH]/(GLfloat)g_nAppPar[APP_HEIGHT],0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);							
	glLoadIdentity();									

	glShadeModel(GL_SMOOTH);							
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				
	glClearDepth(1.0f);									
	glEnable(GL_DEPTH_TEST);							
	glDepthFunc(GL_LEQUAL);								
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	if (!LoadTexture())	
	{
		LogMsg("WARNING ! Texture was not loaded...\n");
	}
	else
	{
		glEnable(GL_TEXTURE_2D);
	}

	return;
}

void CleanUpAndExit(void)
{
	LogMsg("Cleaning up & exit\n");
	OpenGLRelease();
	ChangeDisplaySettings(NULL,0);
	LogClose();
	return;
}

void ReadConfigIniFile(void)
{
	char cPath[MAX_PATH];

	CfgVals cfgval[] =
	{
		{"width",320},
		{"height",240},
		{"depth",32},
		{"zbuff",0},
		{"stencil",0},
		{"fullscr",0}
	};

	GetCurrentDirectory(MAX_PATH,cPath);
	strcat(cPath,CONFIG_NAME);

	LogMsg("...trying to use : %s\n",cPath);

	for (int j=0;j<6;j++)
	{
		g_nAppPar[j] = GetPrivateProfileInt("main",cfgval[j].lpszKeyName,cfgval[j].nDefault,cPath);
	}

	LogMsg("...required : %d*%d %d bpp zbuffer=%d stencil=%d ",
		g_nAppPar[APP_WIDTH],g_nAppPar[APP_HEIGHT],g_nAppPar[APP_DEPTH],
		g_nAppPar[APP_ZDEPTH],g_nAppPar[APP_STENCIL]);

	if (g_nAppPar[APP_FULLSCREEN])
	{
		LogMsg("fullscreen\n");
	}
	else
	{
		LogMsg("windowed\n");
	}
	
	return;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	PAINTSTRUCT ps;

	switch(uMsg)
	{
	case WM_CREATE:

		break;

	case WM_ACTIVATEAPP:

		g_bIsActive = (BOOL)wParam;		
		break;

	case WM_PAINT:
		
		if (BeginPaint(g_hWnd,&ps) != NULL)
		{
			EndPaint(g_hWnd,&ps);
		}

		DrawScreen();

		break;

	case WM_DESTROY:

		CleanUpAndExit();
		PostQuitMessage(0);
		break;

	case WM_KEYDOWN:
		
		switch(wParam)
		{		
		case VK_ADD:

			g_fScale += 0.1;

			if (g_fScale > MAX_SCALE) g_fScale = MAX_SCALE;

			break;

		case VK_SUBTRACT:

			g_fScale -= 0.1;

			if (g_fScale < MIN_SCALE) g_fScale = MIN_SCALE;

			break;			

		case VK_LEFT:

			g_nYaw --;
			if (g_nYaw<=-MAX_ANGLE) g_nYaw = -MAX_ANGLE+1;
			break;

		case VK_RIGHT:

			g_nYaw ++;
			if (g_nYaw>=MAX_ANGLE) g_nYaw = (MAX_ANGLE-1);
			break;

		case VK_UP:

			g_nPitch --;
			if (g_nPitch<=-MAX_ANGLE) g_nPitch = -MAX_ANGLE+1;
			break;

		case VK_DOWN:

			g_nPitch ++;
			if (g_nPitch>=MAX_ANGLE) g_nPitch = (MAX_ANGLE-1);
			break;

		case '1':

			g_nLeftTex++;
			if (g_nLeftTex>g_nMaxTex) g_nLeftTex = 0;
			break;

		case '2':
			
			g_nRightTex++;
			if (g_nRightTex>g_nMaxTex) g_nRightTex = 0;
			break;

		default:
			return DefWindowProc(hwnd,uMsg,wParam,lParam);			
		}

		InvalidateRect(g_hWnd,NULL,FALSE);
		break;

	default:
		return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}

	return 0;
}

BOOL InitInstance(int iWidth,int iHeight,BOOL bFullScreen)
{
	WNDCLASS wc;
	DWORD dwStyle,dwExStyle;
	RECT wr;
	int nx,ny;

	wc.style        = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc  = WndProc;
	wc.cbClsExtra   = 0;
	wc.cbWndExtra   = 0;
	wc.hInstance    = g_hInst;
	wc.hIcon        = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground= (HBRUSH)(COLOR_WINDOW + 2);
	wc.lpszMenuName = NULL;
	wc.lpszClassName= APP_TITLE;
	
	LogMsg("...registering window class\n");

	if (!RegisterClass(&wc))
	{
		return FALSE;
	}

	LogMsg("...setting desired video mode\n");

	if (!SetVideoMode(iWidth,iHeight,g_nAppPar[APP_DEPTH],bFullScreen))
	{
		return FALSE;
	}

	dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

	if (bFullScreen)
	{
		dwExStyle = WS_EX_TOPMOST;
		dwStyle |= WS_POPUP;

		nx = 0;
		ny = 0;

		iWidth = GetSystemMetrics(SM_CXSCREEN);
		iHeight = GetSystemMetrics(SM_CYSCREEN);
	}
	else
	{
		wr.left = 0;
		wr.top 	= 0;
		wr.right = iWidth;
		wr.bottom = iHeight;

		dwExStyle = WS_EX_APPWINDOW;
		dwStyle |= (WS_CAPTION | WS_BORDER | WS_SYSMENU);

		nx = GetSystemMetrics(SM_CXSCREEN)/2 - iWidth/2;
		ny = GetSystemMetrics(SM_CYSCREEN)/2 - iHeight/2;

		AdjustWindowRectEx(&wr,dwStyle,FALSE,dwExStyle);

		iWidth = wr.right - wr.left;
		iHeight = wr.bottom - wr.top;
	}

	LogMsg("...creating window\n");

	g_hWnd = CreateWindowEx(dwExStyle,
		APP_TITLE,
		APP_TITLE,
		dwStyle,
		nx,
		ny,
		iWidth,
		iHeight,
		NULL,
		NULL,
		g_hInst,
		NULL );
	
	if (!g_hWnd)
	{
		return FALSE;
	}

	LogMsg("Initializing OpenGL subsystem\n");
	
	if (!OpenGLInit(&g_nAppPar[APP_DEPTH],&g_nAppPar[APP_ZDEPTH],&g_nAppPar[APP_STENCIL]))
	{
		return FALSE;
	}
	
	return TRUE;
}

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
	MSG msg;

	g_hInst = hInst;

	LogOpen("system.log");

	LogMsg("===System initialization started\n");

	if (hPrevInst)
	{
		LogMsg("...error, previous Instance detected\n");
		CleanUpAndExit();
		return FALSE;
	}

	LogMsg("Reading config values\n");

	ReadConfigIniFile();

	LogMsg("System Init:\n");

	if (!InitInstance(g_nAppPar[APP_WIDTH],g_nAppPar[APP_HEIGHT],g_nAppPar[APP_FULLSCREEN]))
	{
		LogMsg(ERROR_MSG);
		CleanUpAndExit();
		return FALSE;
	}

	LogMsg("Application defined pre-initialization\n");

	ApplicationPreinit();

	ShowWindow(g_hWnd,SW_SHOW);
	UpdateWindow(g_hWnd);
	SetForegroundWindow(g_hWnd);

	LogMsg("===System initialization finished\n");

	while(TRUE)
	{
		if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
		{
			if (!GetMessage(&msg,NULL,0,0))
			{
				return msg.wParam;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			ApplicationCallback();
		}
	}
}