////////////////////////////////////////////////////////////////////////////////
// Main.cpp
//
//  Main program logic.

#include "stdhdr.h"

#include "Debug.h"
#include "Sound.h"
#include "Input.h"
#include "Graphics.h"
#include "Window.h"
#include "MP3.h"

////////////////////////////////////////////////////////////////////////////////
// DirectX Audio

IDirectMusicSegment8    *g_pBackgroundMusic;
bool                    g_bMusicPlaying, g_bFinishedInit;
bool                    g_bMusicEnabled;

////////////////////////////////////////////////////////////////////////////////
// DirectInput

// {BD0E8406-FB56-4322-8BC6-BD6E481F5564}
GUID g_guidApp = 
{ 0xbd0e8406, 0xfb56, 0x4322, { 0x8b, 0xc6, 0xbd, 0x6e, 0x48, 0x1f, 0x55, 0x64 } };
DWORD   g_dwGenre = DIVIRTUAL_ARCADE_SIDE2SIDE;
LPCTSTR g_tszActionMapName = _T("Sample");

enum Actions 
{
    ACTIONS_LEFTRIGHT,
    ACTIONS_LEFT,
    ACTIONS_RIGHT,
    ACTIONS_QUIT,
    ACTIONS_HELP,
    ACTIONS_PAUSE,
    ACTIONS_MODESWITCH,
    ACTIONS_NONE
};

bool    g_bQuit;
bool    g_bLeft, g_bRight, g_bShowHelp, g_bPaused;

DIACTION g_rgActions[] =
{
    // Genre-defined virtual axes
    { ACTIONS_LEFTRIGHT,    DIAXIS_ARCADES_LATERAL,             0,  "Left/Right" },

    // Actions mapped to keys as well as to virtual controls
    { ACTIONS_LEFT,         DIKEYBOARD_LEFT,                    0,  "Left" },
    { ACTIONS_LEFT,         DIKEYBOARD_NUMPAD4,                 0,  "Left" },
    { ACTIONS_RIGHT,        DIKEYBOARD_RIGHT,                   0,  "Right" },
    { ACTIONS_RIGHT,        DIKEYBOARD_NUMPAD6,                 0,  "Right" },
    { ACTIONS_PAUSE,        DIKEYBOARD_P,                       0,  "Pause" },
    { ACTIONS_MODESWITCH,   DIKEYBOARD_M,           DIA_APPFIXED,   "Full screen/Windowed" },
    { ACTIONS_HELP,         DIKEYBOARD_F1,          DIA_APPFIXED,   "Help" },

    // Actions mapped to keys
    { ACTIONS_QUIT,         DIKEYBOARD_ESCAPE,      DIA_APPFIXED,   "Quit" },
};

DWORD g_nActions = sizeof(g_rgActions) / sizeof(DIACTION);

////////////////////////////////////////////////////////////////////////////////
// DirectX Graphics

IDirect3DTexture8   *pBackgroundTexture, *pSpriteTexture;

int nBackground, nFixedSprite, nMovingSprite, nPlayerSprite;

BOOL    g_bFullScreen = TRUE;

////////////////////////////////////////////////////////////////////////////////
// Music handling

void PlayBackgroundMusic()
{
    if ((g_pBackgroundMusic != NULL) && !g_bMusicPlaying && g_bFinishedInit && g_bMusicEnabled)
    {
        // Play the background music
        TRACE0("Playing background music...\n");
        g_bMusicPlaying = true;
        PlaySound(g_pBackgroundMusic);
    }
}

void StopBackgroundMusic()
{
    StopAllSound();
    g_bMusicPlaying = false;
}

// Called when an MP3 file finishes playing
void OnMP3Finish(long)
{
}

////////////////////////////////////////////////////////////////////////////////
// Input handling

#define AXIS_THRESHOLD  20

void HandleAction(UINT nAction, DWORD dwData)
{
    int nAxisPos = (int)dwData;

    switch (nAction)
    {
    case ACTIONS_LEFTRIGHT:
        if (nAxisPos < -AXIS_THRESHOLD)
        {
            g_bLeft = true;
            g_bRight = false;
        }
        else if (nAxisPos > AXIS_THRESHOLD)
        {
            g_bRight = true;
            g_bLeft = false;
        }
        else
        {
            g_bLeft = g_bRight = false;
        }
        break;
    
    case ACTIONS_LEFT:
        g_bLeft = (dwData != 0);
        break;

    case ACTIONS_RIGHT:
        g_bRight = (dwData != 0);
        break;

    case ACTIONS_QUIT:
        g_bQuit = true;
        break;

    case ACTIONS_HELP:
        if (dwData != 0)
            g_bShowHelp = true;
        break;

    case ACTIONS_PAUSE:
        if (dwData != 0)
            g_bPaused = !g_bPaused;
        break;

    case ACTIONS_MODESWITCH:
        if (dwData != 0)
        {
            // Switch between full-screen and windowed mode
            ReleaseVertexBuffer();
            CloseDevice();
            
            g_bFullScreen = !g_bFullScreen;

            InitDevice(g_bFullScreen);
            
            // Reload our textures.
            pBackgroundTexture = LoadTexture(_T("a.bmp"));
            SetObjectTexture(nBackground, pBackgroundTexture);
            pSpriteTexture = LoadTexture(_T("sprites.dds"));
            SetObjectTexture(nFixedSprite, pSpriteTexture);
            SetObjectTexture(nMovingSprite, pSpriteTexture);
            SetObjectTexture(nPlayerSprite, pSpriteTexture);
            
            CreateVertexBuffer();
        }
        break;
    
    
    default:
        break;
    }
}

////////////////////////////////////////////////////////////////////////////////
// Idle-time processing function.

int xAutomaticSprite;
int xPlayer;

void DrawFrame()
{
    DEBUG_TIMING_START();
    MoveObject(nMovingSprite, 288 + xAutomaticSprite, 100);
    MoveObject(nPlayerSprite, 288 + xPlayer, 150);
    RefreshVertexBuffer();

    BeginScene();
    BeginDrawingObjects();

    DrawObject(nBackground);
    DrawObject(nFixedSprite);
    DrawObject(nMovingSprite);
    DrawObject(nPlayerSprite);
    
    EndScene();
    DEBUG_TIMING_END("Scene draw");
    Flip();
}

void OnIdle(void)
{
    if (g_pd3dDevice == NULL)
        return;

    if (!g_bActive)
        return;

    CheckInput();

    if (g_bQuit)
    {
        PostMessage(hWndMain, WM_CLOSE, 0, 0);
        return;
    }
    if (g_bShowHelp)
    {
        StopAllSound();
        g_bMusicPlaying = false;
        g_bShowHelp = false;
        DisplayInput();
        // Music came back on when we were reactivated...
    }

    if (!g_bPaused)
    {
        // Move a sprite around automatically.
        xAutomaticSprite++;
        if (xAutomaticSprite > 100)
            xAutomaticSprite = -100;

        // Move a sprite around with the input.
        if (g_bLeft)
            xPlayer--;
        if (g_bRight)
            xPlayer++;
    }
    
    DrawFrame();
}

////////////////////////////////////////////////////////////////////////////////
// Initialisation and shutdown

BOOL InitApplication(HINSTANCE hInstance)
{
    if (!InitWindow("DirectX Sample Application with DirectX Graphics"))
        return FALSE;

    if (!InitDirectMusic())
        return FALSE;

    // Load the background music
    g_pBackgroundMusic = LoadSound(L"passport.mid");
    if (g_pBackgroundMusic == NULL)
    {
        ExitDirectMusic();
        DISPLAYERROR("Could not load background music.");
        return FALSE;
    }
    // Standard MIDI file
    g_pBackgroundMusic->SetParam(GUID_StandardMIDIFile, 
        0xFFFFFFFF, DMUS_SEG_ALLTRACKS, 0, NULL);
    // Repeat forever
    g_pBackgroundMusic->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
    // Download it, ready for playback
    DownloadSound(g_pBackgroundMusic);
    g_bMusicEnabled = true;

    if (!InitDirectInput())
    {
        DISPLAYERROR("Failed to initialise DirectInput.");
        ExitDirectMusic();
        return FALSE;
    }
    if (!InitDirectXGraphics())
    {
        ExitDirectInput();
        ExitDirectMusic();
        return FALSE;
    }

    // Initialise sprites.
    SetObjectBufferSize(4);

    // Load our textures.
    pBackgroundTexture = LoadTexture(_T("a.bmp"));
    if (pBackgroundTexture == NULL)
    {
        ExitDirectXGraphics();
        
        DISPLAYERROR("Could not load background image.");
        return FALSE;
    }
    pSpriteTexture = LoadTexture(_T("sprites.dds"));
    if (pSpriteTexture == NULL)
    {
        ExitDirectXGraphics();
        
        DISPLAYERROR("Could not load sprites.");
        return FALSE;
    }

    nBackground = CreateRectangularObject(0, 0, 640, 480, pBackgroundTexture, 0, 0);
    nFixedSprite = CreateRectangularObject(288, 208, 64, 64, pSpriteTexture, 128, 0);
    nMovingSprite = CreateRectangularObject(288, 100, 64, 64, pSpriteTexture, 0, 0);
    nPlayerSprite = CreateRectangularObject(288, 150, 64, 64, pSpriteTexture, 64, 0);

    CreateVertexBuffer();

    AcquireDevices();

    // Now configure the input devices.
    ConfigureInput();

    TRACE0("Finished initialisation...\n");
    g_bFinishedInit = true;
    return TRUE;
}

void OnClose()
{
    StopBackgroundMusic();

    // Release our textures.
    pBackgroundTexture->Release();
    pBackgroundTexture = NULL;
    pSpriteTexture->Release();
    pSpriteTexture = NULL;

    ReleaseVertexBuffer();
    ReleaseObjectBuffer();

    ExitDirectXGraphics();

    UnloadSound(g_pBackgroundMusic);
    g_pBackgroundMusic->Release();
    g_pBackgroundMusic = NULL;
    ExitDirectMusic();

    UnacquireDevices();
    ExitDirectInput();
}

// Program entry point.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) 
{
    if (!InitApplication(hInstance))
        return 1;

    // Play the background music
    PlayBackgroundMusic();

    Run();

    return 0;
}