#include "main.h"

HWND g_hndWindow;
HDC g_hndDC;
HGLRC g_hndRC;
int g_iWinWidth = 0, g_iWinHeight = 0;
bool g_bKillApp = false;
bool g_bFullscreen = false;
int g_iFPS = 0;
float g_fTimeMod = 0.0f;

HANDLE l_hndConsoleInput, l_hndConsoleOutput;

void cprintf(unsigned int a_uiColor, char *a_szString, ...)
{
	va_list argList;
	char cBuffer[256];
	
    va_start(argList, a_szString);
    vsprintf(cBuffer, a_szString, argList);
    va_end(argList);

	SetConsoleTextAttribute(l_hndConsoleOutput, a_uiColor);
 	printf(cBuffer);
	SetConsoleTextAttribute(l_hndConsoleOutput, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

float Interpolate(float a_fStart, float a_fStop, float a_fTime)
{
    return ((1.0f - a_fTime) * a_fStart) + (a_fTime * a_fStop);
}

LRESULT CALLBACK WinProc(HWND a_hndWindow, UINT a_Message, WPARAM a_wParam, LPARAM a_lParam)
{
    switch(a_Message)
    {
        case WM_CREATE:
        {
            return 0;
        }

        //Input.
        case WM_KEYDOWN:
        {
            return 0;
        }

        case WM_KEYUP:
        {
            if(a_wParam == VK_ESCAPE)
            {
                g_bKillApp = true;
            }
            return 0;
        }
          
        case WM_CLOSE:
        case WM_DESTROY:
        {            
            PostQuitMessage(0);
            g_bKillApp = true;
            return 0;
        }
    }

    return DefWindowProc(a_hndWindow, a_Message, a_wParam, a_lParam);
}

void InitWindow(char *a_szTitle = "App", int a_iWidth = 640, int a_iHeight = 480, bool a_bFullscreen = false)
{
    g_iWinWidth = a_iWidth;
    g_iWinHeight = a_iHeight;
    g_bFullscreen = a_bFullscreen;
    
    l_hndConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
	l_hndConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    WNDCLASSEX wndclassex = {0};

    wndclassex.cbSize = sizeof(WNDCLASSEX);
    wndclassex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wndclassex.lpfnWndProc = WinProc;
    wndclassex.hInstance = GetModuleHandle(NULL);
    wndclassex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclassex.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    wndclassex.lpszClassName = WINDOWCLASS;

    RegisterClassEx(&wndclassex);

    DWORD dwStyle;

    dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;

	if(g_bFullscreen)								// 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	= g_iWinWidth;			// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= g_iWinHeight;			// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= 32;				// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			MessageBox(NULL,"Can't set fullscreen, quitting.","ERROR",MB_ICONEXCLAMATION);
			g_bKillApp = true;
			return;
		}
	
		dwStyle=WS_POPUP;
		ShowCursor(false);
	}	

	RECT WindowRect;
	WindowRect.left=(long)0;
	WindowRect.right=(long)g_iWinWidth;
	WindowRect.top=(long)0;
	WindowRect.bottom=(long)g_iWinHeight;

	AdjustWindowRectEx(&WindowRect, dwStyle, false, WS_EX_APPWINDOW);

    g_hndWindow = CreateWindowEx(WS_EX_APPWINDOW,
                                                wndclassex.lpszClassName,
                                                a_szTitle,
                                                dwStyle,
                                                0,
                                                0,
                                                g_iWinWidth,
                                                g_iWinHeight,
                                                NULL,
                                                NULL,
                                                NULL,
                                                NULL);
    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
        32,								            // 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
    };

    g_hndDC = GetDC(g_hndWindow);

    unsigned int uiPixelFormat;
    uiPixelFormat = ChoosePixelFormat(g_hndDC, &pfd);
    SetPixelFormat(g_hndDC, uiPixelFormat, &pfd);
    g_hndRC = wglCreateContext(g_hndDC);
    wglMakeCurrent(g_hndDC, g_hndRC);
   	
/*	if(bFullscreen == true)
		glViewport(0, 0, iSizex, iSizey);
	else*/
//        glViewport(0, 0, g_iWinWidth, g_iWinHeight - 24);

    glViewport(0, 0, g_iWinWidth, g_iWinHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f, g_iWinWidth / g_iWinHeight, 1.0f, 1000.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //glEnable(GL_NORMALIZE);
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glPolygonMode(GL_BACK, GL_LINE);
    glPolygonMode(GL_FRONT, GL_FILL);
    glEnable(GL_TEXTURE_2D);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

    ShowWindow(g_hndWindow, true);
    UpdateWindow(g_hndWindow);
}

void FadeIn(void)
{
    static uint uiLastTick = GetTickCount();

    if(GetTickCount() - uiLastTick > 1000) return;

    float fMod = 1.0f - ((GetTickCount() - uiLastTick) / 1000.0f); 
    
    glEnable(GL_BLEND);
    glLoadIdentity();
    glColor4f(0.0f, 0.0f, 0.0f, fMod);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2d(0, 0);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2d(g_iWinWidth, 0);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2d(g_iWinWidth, g_iWinHeight);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2d(0, g_iWinHeight);
    glEnd();    
}

bool FadeOut(void)
{
    static uint uiLastTick = GetTickCount();
    float fMod = ((GetTickCount() - uiLastTick) / 1000.0f); 
    
    if(fMod > 1.0f) fMod = 1.0f;
    
    glEnable(GL_BLEND);
    glLoadIdentity();
    glColor4f(0.0f, 0.0f, 0.0f, fMod);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 1.0f);
        glVertex2d(0, 0);
        glTexCoord2f(1.0f, 1.0f);
        glVertex2d(g_iWinWidth, 0);
        glTexCoord2f(1.0f, 0.0f);
        glVertex2d(g_iWinWidth, g_iWinHeight);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2d(0, g_iWinHeight);
    glEnd();  
    
    FadeSound();
    
    if(fMod >= 1.0f)
        return true;
    return false;  
}

void DoLoop(void)
{
    static uint uiLastTick = GetTickCount();
    static int iFramesDrawn = 0;
             
    GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
    GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
    GLfloat LightPosition[]= { -38.0f, 10.0f, 38.0f, 1.0f };	
    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
    glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);    
    glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.5f);
    glEnable(GL_LIGHT1);
    
    bool bDie = false;
    while(!bDie)
    {                      
        MSG msg;                
    
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	
    	glLoadIdentity();
    	
    	static float fRot = 0.0f;
        fRot += 10.0f * g_fTimeMod;
        if(fRot > 360.0f) fRot = 0.0f;
    
    	static float fRot2 = 0.0f;
        float fMovex = 0.0f, fMovey = 0.0f;
        fRot2 += 20.0f * g_fTimeMod;
        if(fRot2 > 360.0f) fRot2 = 0.0f;
        fMovex = cosf((360.0f - fRot2) * (3.14f / 180.0f)) * 2.5f;
        fMovey = sinf((360.0f - fRot2) * (3.14f / 180.0f)) * 2.5f;
        	
    	glRotatef(36.0f, 1.0f, 0.0f, 0.0f);
    	glRotatef(fRot, 0.0f, 1.0f, 0.0f);
    	
    	glTranslatef(-38.0f + fMovex, -10.0f, 38.0f + fMovey);

        glPushMatrix();
    	DrawDisplayGrid();

        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(0, g_iWinWidth, 0, g_iWinHeight, -1, 9999);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

        glDisable(GL_DEPTH_TEST);
        DrawText();
    	DrawLetterBox();
    	DrawSideBars();
        DrawVU();
        FadeIn();
        if(g_bKillApp == true) bDie = FadeOut();
        glEnable(GL_DEPTH_TEST);

        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();

    	glPopMatrix();

	    glFlush();
        SwapBuffers(g_hndDC);
        
        ++iFramesDrawn;
        if(GetTickCount() - uiLastTick > 1000)
        {
            g_fTimeMod = 1.0f / (float)iFramesDrawn;
            g_iFPS = iFramesDrawn;
            iFramesDrawn = 0;
            uiLastTick = GetTickCount();
        }
    }    
}

void KillWindow(void)
{
    if(g_hndRC != NULL)
    {
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(g_hndRC);
    }

    if(g_hndWindow != NULL)
    {
        DestroyWindow(g_hndWindow);
        UnregisterClass(WINDOWCLASS, NULL);
    }

    g_hndRC = NULL;
    g_hndDC = NULL;
    g_hndWindow = NULL;

    ShowCursor(true);
    if(g_bFullscreen == true) ChangeDisplaySettings(NULL,0);
}

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)
{
    srand(time(NULL));                
                    
    InitWindow("Intro App", 1024, 768, true);
    Sleep(1000);
    InitDisplayGrid();
    InitLetterBox();
    InitSideBars();
    InitSound();
    InitVU();
    InitText();
    
    RunSound();    
    DoLoop();
    
    KillSound();
    KillWindow();
    return 0;
}
