#include <math.h>
#include <stdio.h>

#include <d3dx8.h>

#include <algorithm>

#include "Timer.h"

#include ".\LD.h"
#include "GSMenu.h"
#include "resource.h"

#include <ctime>


#pragma comment( lib, "d3d8.lib" )
#pragma comment( lib, "d3dx8.lib" )
#pragma comment( lib, "dsound.lib" )


LDApp       theApp;


float     Rotation = 0.0f;



LDApp::LDApp() :
  m_pd3d( NULL ),
  m_pd3dDevice( NULL ),
  m_pTextureFont( NULL ),
  m_pCurrentGameState( NULL ),
  m_pNextState( NULL ),
  m_pFont( NULL ),
  m_pDirectSound( NULL ),
  m_WavyTextTimeCount( 0.0f ),
  m_hIcon( NULL ),
  m_FullScreen( false ),
  m_FixedFrameDelay( 0.0f )
{
  memset( &m_d3dPP, 0, sizeof( m_d3dPP ) );

  for ( int i = 0; i < 256; ++i )
  {
    m_KeyPressed[i] = false;
    m_KeyReleased[i] = true;
  }

  m_hIcon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON_BOMB ) );

  srand( (unsigned int)std::time( NULL ) );
}



LDApp::~LDApp()
{
  if ( m_hIcon )
  {
    DestroyIcon( m_hIcon );
  }
}



LRESULT LDApp::StaticWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
  return theApp.WindowProc( hWnd, uMsg, wParam, lParam );
}



void LDApp::ToggleWindowMode()
{
  m_FullScreen          = !m_FullScreen;
  m_d3dPP.Windowed      = !m_FullScreen;

  DWORD       NewStyle    = WS_VISIBLE;
  DWORD       NewStyleEx  = 0;
  if ( m_FullScreen )
  {
    NewStyle |= WS_POPUP;
    NewStyleEx |= WS_EX_TOPMOST;

    // store previous position
    GetWindowPlacement( m_hWnd, &m_WPLWindowed );
    RECT    rc;

    GetWindowRect( m_hWnd, &rc );

    m_WindowPosWindowed.x = rc.left;
    m_WindowPosWindowed.y = rc.top;
  }
  else
  {
    NewStyle |= WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_OVERLAPPED;
    NewStyleEx = WS_EX_WINDOWEDGE;
  }
  // First volatile resources must be re-acquired
  SetWindowLong( m_hWnd, GWL_STYLE, NewStyle );
  SetWindowLong( m_hWnd, GWL_EXSTYLE, NewStyleEx );

  // Direct3D device can then be reset properly
  Unload3dResources();
  m_pd3dDevice->Reset( &m_d3dPP );

  if ( !m_FullScreen )
  {
    SetWindowPlacement( m_hWnd, &m_WPLWindowed );
    SetWindowPos( m_hWnd, HWND_NOTOPMOST, m_WindowPosWindowed.x, m_WindowPosWindowed.y,
                  0, 0, SWP_NOSIZE | SWP_FRAMECHANGED );
  }
  else
  {
    SetWindowPos( m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
  }
  // Once the main device is reset, the subdevices can also be reset
  Load3dResources();
}



LRESULT LDApp::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
  switch ( uMsg )
  {
    case WM_KEYDOWN:
      m_KeyPressed[wParam] = true;
      if ( m_pCurrentGameState )
      {
        m_pCurrentGameState->OnKeyDown( (int)wParam );
      }
      break;
    case WM_KEYUP:
      m_KeyPressed[wParam] = false;
      m_KeyReleased[wParam] = true;
      break;
    case WM_CHAR:
      if ( m_pCurrentGameState )
      {
        m_pCurrentGameState->OnChar( (int)wParam );
      }
      break;
    case WM_SYSKEYUP:
      if ( wParam == VK_RETURN )
      {
        // Toggle Windowed/Fullscreen mode
        ToggleWindowMode();
        return 0;
      }
      break;
    case WM_MOUSEMOVE:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_LBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
    case WM_RBUTTONDBLCLK:
      m_MouseX = (int)(short)LOWORD( lParam );
      m_MouseY = (int)(short)HIWORD( lParam );
      m_MouseButtons = (int)wParam;
      if ( m_pCurrentGameState )
      {
        m_pCurrentGameState->OnMouse( (int)(short)LOWORD( lParam ), (int)(short)HIWORD( lParam ), (int)wParam );
      }
      break;
    //case WM_MOUSEWHEEL:
    case 0x020a:
      // WM_MOUSEWHEEL
      if ( m_pCurrentGameState )
      {
        int   Delta = ( (short)HIWORD( wParam ) );

        UINT  Ticks = 0;

        SystemParametersInfo( 104, 0, &Ticks, 0 );

        while ( Delta >= 120 )
        {
          for ( UINT i = 0; i < Ticks; ++i )
          {
            m_pCurrentGameState->OnMouseWheel( 1 );
          }
          Delta -= 120;
        }
        while ( Delta <= -120 )
        {
          for ( UINT i = 0; i < Ticks; ++i )
          {
            m_pCurrentGameState->OnMouseWheel( -1 );
          }
          Delta += 120;
        }
      }
      break;
    case WM_DESTROY:
      PostQuitMessage( 0 );
      return TRUE;
  }
  return DefWindowProc( hWnd, uMsg, wParam, lParam );
}



void LDApp::RenderFrame()
{
  m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
  m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
  m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 8 );

  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );

  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT );

  //m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff757E85, 1.0f, 0 );
  m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff757E85, 1.0f, 0 );

  if ( m_pCurrentGameState )
  {
    m_pCurrentGameState->Display( m_pd3dDevice );
  }

  m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

  /*
  D3DXMATRIX      MatWorld;  
  D3DXMATRIX      MatView;  
  D3DXMATRIX      MatProj;  

  D3DXVECTOR3     m_CameraPos( 0.0f, 0.0f, 10.0f );

  //D3DXMatrixIdentity( &MatWorld );

  D3DXMatrixRotationX( &MatWorld, Rotation );
  D3DXMatrixLookAtLH( &MatView, 
                      &m_CameraPos,
                      &( m_CameraPos + D3DXVECTOR3( 0.0f, 0.0f, -5.0f ) ),
                      &D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) );

  D3DXMatrixPerspectiveFovLH( &MatProj, D3DXToRadian( 90 ), 640.0f / 480.0f, 0.01f, 100.0f );

  m_pd3dDevice->SetTransform( D3DTS_WORLD, &MatWorld );
  m_pd3dDevice->SetTransform( D3DTS_VIEW, &MatView );
  m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &MatProj );
  m_pd3dDevice->SetTexture( 0, NULL );

  m_pTestVB->Display( m_pd3dDevice );

  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT );*/
}



void LDApp::Print( int X, int Y, const char* szText, DWORD Color )
{
  if ( m_pFont == NULL )
  {
    return;
  }

  if ( SUCCEEDED( m_pFont->Begin() ) )
  {
    RECT    rcText;

    SetRect( &rcText, X, Y, 1024, 768 );
    m_pFont->DrawTextA( szText, (int)strlen( szText ), &rcText, 0, Color );
    m_pFont->End();
  }
}



void LDApp::PrintNice( int X, int Y, const char* szText, DWORD Color )
{
  while ( *szText )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szText ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      RenderTextureSection2d( X, Y, tsLetter, Color );

      X += tsLetter.Width;
    }

    ++szText;
  }
}



void LDApp::PrintNiceCentered( int X, int Y, const char* szText, DWORD Color, bool bWavy )
{
  if ( bWavy )
  {
    PrintNiceCenteredWavy( X, Y, szText, Color );
    return;
  }

  int   length = 0;

  const char*   szDummy = szText;

  while ( *szDummy )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szDummy ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      length += tsLetter.Width;
    }

    ++szDummy;
  }

  // center about the x value
  X -= length / 2;
  while ( *szText )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szText ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      RenderTextureSection2d( X, Y, tsLetter, Color );

      X += tsLetter.Width;
    }

    ++szText;
  }
}



void LDApp::PrintNiceRightAligned( int X, int Y, const char* szText, DWORD Color )
{
  int   length = 0;

  const char*   szDummy = szText;

  while ( *szDummy )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szDummy ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      length += tsLetter.Width;
    }

    ++szDummy;
  }

  // center about the x value
  X -= length;
  while ( *szText )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szText ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      RenderTextureSection2d( X, Y, tsLetter, Color );

      X += tsLetter.Width;
    }

    ++szText;
  }
}



void LDApp::PrintNiceCenteredWavy( int X, int Y, const char* szText, DWORD Color )
{
  int   length = 0;

  const char*   szDummy = szText;

  while ( *szDummy )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szDummy ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      length += tsLetter.Width;
    }

    ++szDummy;
  }

  // center about the x value
  X -= length / 2;

  int   iLetter = 0;

  while ( *szText )
  {
    tMapLetters::iterator   itLetter( m_mapLetters.find( *szText ) );
    if ( itLetter != m_mapLetters.end() )
    {
      tTextureSection& tsLetter = itLetter->second;

      // make waves, different side every odd letter
      RenderTextureSection2d( X, Y + ( 1 - ( iLetter % 2 ) * 2 ) * (int)( 4.0f * cosf( m_WavyTextTimeCount * 3.1415926f / 180.0f ) ), tsLetter, Color );

      X += tsLetter.Width;
      ++iLetter;
    }
    ++szText;
  }
}



void LDApp::RenderTextureSection2d( int X, int Y,
                                          const tTextureSection& TexSection,
                                          DWORD Color,
                                          DWORD Color2,
                                          DWORD Color3,
                                          DWORD Color4,
                                          int Width, int Height,
                                          DWORD AlternativeFlags )
{
  m_pd3dDevice->SetTexture( 0, TexSection.pTexture );

  if ( Width == -1 )
  {
    Width  = TexSection.Width;
  }
  if ( Height == -1 )
  {
    Height = TexSection.Height;
  }

  if ( AlternativeFlags == 0 )
  {
    AlternativeFlags = TexSection.Flags;
  }

  if ( ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  ||   ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_90 ) )
  {
    std::swap( Width, Height );
  }

  if ( AlternativeFlags & tTextureSection::TSF_HCENTER )
  {
    X -= Width / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_VCENTER )
  {
    Y -= Height / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_BOTTOM )
  {
    Y -= Height - 1;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_RIGHT )
  {
    X -= Width - 1;
  }

  float   TU[2][2] = { { TexSection.TU[0], TexSection.TU[0] }, { TexSection.TU[1], TexSection.TU[1] } },
          TV[2][2] = { { TexSection.TV[0], TexSection.TV[1] }, { TexSection.TV[0], TexSection.TV[1] } };


  if ( AlternativeFlags & tTextureSection::TSF_H_MIRROR )
  {
    std::swap( TU[0][0], TU[1][0] );
    std::swap( TU[0][1], TU[1][1] );
  }
  if ( AlternativeFlags & tTextureSection::TSF_V_MIRROR )
  {
    std::swap( TV[0][0], TV[0][1] );
    std::swap( TV[1][0], TV[1][1] );
  }

  if ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[0][1];
    TV[0][0] = TV[0][1];
    TU[0][1] = TU[1][1];
    TV[0][1] = TV[1][1];
    TU[1][1] = TU[1][0];
    TV[1][1] = TV[1][0];
    TU[1][0] = TempTU;
    TV[1][0] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_90 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[1][0];
    TV[0][0] = TV[1][0];
    TU[1][0] = TU[1][1];
    TV[1][0] = TV[1][1];
    TU[1][1] = TU[0][1];
    TV[1][1] = TV[0][1];
    TU[0][1] = TempTU;
    TV[0][1] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_180 )
  {
    std::swap( TU[0][0], TU[1][1] );
    std::swap( TV[0][0], TV[1][1] );
    std::swap( TU[1][0], TU[0][1] );
    std::swap( TV[1][0], TV[0][1] );
  }

  RenderQuad2d( X, Y,
              Width, Height,
              TU[0][0], TV[0][0],
              TU[1][0], TV[1][0],
              TU[0][1], TV[0][1],
              TU[1][1], TV[1][1],
              Color,
              Color2, Color3, Color4 );
}



void LDApp::RenderTextureSectionAsTile2d( int X, int Y,
                                          const tTextureSection& TexSection,
                                          DWORD Color )
{
  RenderTextureSection2d( X, Y, TexSection, Color, Color, Color, Color, 32, 32 );
}



void LDApp::RenderTextureSectionRotated2d( int X, int Y,
                                                 const tTextureSection& TexSection,
                                                 float Angle,
                                                 DWORD Color,
                                                 DWORD Color2,
                                                 DWORD Color3,
                                                 DWORD Color4,
                                                 int Width, int Height,
                                                 DWORD AlternativeFlags )
{
  m_pd3dDevice->SetTexture( 0, TexSection.pTexture );

  if ( Width == -1 )
  {
    Width = TexSection.Width;
  }
  if ( Height == -1 )
  {
    Height = TexSection.Height;
  }

  if ( AlternativeFlags == 0 )
  {
    AlternativeFlags = TexSection.Flags;
  }

  if ( ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  ||   ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_90 ) )
  {
    std::swap( Width, Height );
  }

  if ( AlternativeFlags & tTextureSection::TSF_HCENTER )
  {
    X -= Width / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_VCENTER )
  {
    Y -= Height / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_BOTTOM )
  {
    Y -= Height - 1;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_RIGHT )
  {
    X -= Width - 1;
  }

  float   TU[2][2] = { { TexSection.TU[0], TexSection.TU[0] },{ TexSection.TU[1], TexSection.TU[1] } },
    TV[2][2] = { { TexSection.TV[0], TexSection.TV[1] },{ TexSection.TV[0], TexSection.TV[1] } };


  if ( AlternativeFlags & tTextureSection::TSF_H_MIRROR )
  {
    std::swap( TU[0][0], TU[1][0] );
    std::swap( TU[0][1], TU[1][1] );
  }
  if ( AlternativeFlags & tTextureSection::TSF_V_MIRROR )
  {
    std::swap( TV[0][0], TV[0][1] );
    std::swap( TV[1][0], TV[1][1] );
  }

  if ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[0][1];
    TV[0][0] = TV[0][1];
    TU[0][1] = TU[1][1];
    TV[0][1] = TV[1][1];
    TU[1][1] = TU[1][0];
    TV[1][1] = TV[1][0];
    TU[1][0] = TempTU;
    TV[1][0] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_90 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[1][0];
    TV[0][0] = TV[1][0];
    TU[1][0] = TU[1][1];
    TV[1][0] = TV[1][1];
    TU[1][1] = TU[0][1];
    TV[1][1] = TV[0][1];
    TU[0][1] = TempTU;
    TV[0][1] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_180 )
  {
    std::swap( TU[0][0], TU[1][1] );
    std::swap( TV[0][0], TV[1][1] );
    std::swap( TU[1][0], TU[0][1] );
    std::swap( TV[1][0], TV[0][1] );
  }

  RenderQuadRotated2d( X, Y,
                     Width, Height,
                     TU[0][0], TV[0][0],
                     TU[1][0], TV[1][0],
                     TU[0][1], TV[0][1],
                     TU[1][1], TV[1][1],
                     Angle,
                     Color,
                     Color2, Color3, Color4 );
}



void LDApp::RenderTextureSectionRotated2d( int X, int Y,
                                           const tTextureSection& TexSection,
                                           float Angle,
                                           float ZoomFactor,
                                           DWORD Color,
                                           DWORD Color2,
                                           DWORD Color3,
                                           DWORD Color4,
                                           int Width, int Height,
                                           DWORD AlternativeFlags )
{
  m_pd3dDevice->SetTexture( 0, TexSection.pTexture );

  if ( Width == -1 )
  {
    Width = TexSection.Width;
  }
  if ( Height == -1 )
  {
    Height = TexSection.Height;
  }

  if ( AlternativeFlags == 0 )
  {
    AlternativeFlags = TexSection.Flags;
  }

  if ( ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
       || ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_90 ) )
  {
    std::swap( Width, Height );
  }

  if ( AlternativeFlags & tTextureSection::TSF_HCENTER )
  {
    X -= Width / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_VCENTER )
  {
    Y -= Height / 2;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_BOTTOM )
  {
    Y -= Height - 1;
  }
  if ( AlternativeFlags & tTextureSection::TSF_ALIGN_RIGHT )
  {
    X -= Width - 1;
  }

  float   TU[2][2] = { { TexSection.TU[0], TexSection.TU[0] },{ TexSection.TU[1], TexSection.TU[1] } },
    TV[2][2] = { { TexSection.TV[0], TexSection.TV[1] },{ TexSection.TV[0], TexSection.TV[1] } };


  if ( AlternativeFlags & tTextureSection::TSF_H_MIRROR )
  {
    std::swap( TU[0][0], TU[1][0] );
    std::swap( TU[0][1], TU[1][1] );
  }
  if ( AlternativeFlags & tTextureSection::TSF_V_MIRROR )
  {
    std::swap( TV[0][0], TV[0][1] );
    std::swap( TV[1][0], TV[1][1] );
  }

  if ( ( AlternativeFlags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[0][1];
    TV[0][0] = TV[0][1];
    TU[0][1] = TU[1][1];
    TV[0][1] = TV[1][1];
    TU[1][1] = TU[1][0];
    TV[1][1] = TV[1][0];
    TU[1][0] = TempTU;
    TV[1][0] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_90 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[1][0];
    TV[0][0] = TV[1][0];
    TU[1][0] = TU[1][1];
    TV[1][0] = TV[1][1];
    TU[1][1] = TU[0][1];
    TV[1][1] = TV[0][1];
    TU[0][1] = TempTU;
    TV[0][1] = TempTV;
  }
  else if ( AlternativeFlags & tTextureSection::TSF_ROTATE_180 )
  {
    std::swap( TU[0][0], TU[1][1] );
    std::swap( TV[0][0], TV[1][1] );
    std::swap( TU[1][0], TU[0][1] );
    std::swap( TV[1][0], TV[0][1] );
  }

  RenderQuadRotated2d( X, Y,
                       Width, Height,
                       TU[0][0], TV[0][0],
                       TU[1][0], TV[1][0],
                       TU[0][1], TV[0][1],
                       TU[1][1], TV[1][1],
                       Angle,
                       ZoomFactor,
                       Color,
                       Color2, Color3, Color4 );
}



void LDApp::RenderQuad( const D3DXVECTOR3& V1,
                          const D3DXVECTOR3& V2,
                          const D3DXVECTOR3& V3,
                          const D3DXVECTOR3& V4,
                          float TU1, float TV1,
                          float TU2, float TV2,
                          float TU3, float TV3,
                          float TU4, float TV4,
                          DWORD Color,
                          DWORD Color2,
                          DWORD Color3,
                          DWORD Color4 )
{
  if ( ( Color2 == Color3 )
  &&   ( Color3 == Color4 )
  &&   ( Color4 == 0 ) )
  {
    Color2 = Color3 = Color4 = Color;
  }

  struct CUSTOMVERTEX
  {
    D3DXVECTOR3     position; // The position
    D3DXVECTOR3     normal; // The position
    D3DCOLOR        color;    // The color
    float           fTU,
                    fTV;
  };

  CUSTOMVERTEX          vertData[4];


  D3DXVECTOR3       normal;

  D3DXVec3Cross( &normal, &( V2 - V1 ), &( V3 - V1 ) );
  D3DXVec3Normalize( &normal, &normal );

  m_pd3dDevice->SetVertexShader( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_NORMAL );

  vertData[0].position    = V1;
  vertData[0].color       = Color;
  vertData[0].normal      = normal;
  vertData[0].fTU         = TU1;
  vertData[0].fTV         = TV1;

  vertData[1].position    = V2;
  vertData[1].color       = Color2;
  vertData[1].normal      = normal;
  vertData[1].fTU         = TU2;
  vertData[1].fTV         = TV2;

  vertData[2].position    = V3;
  vertData[2].color       = Color3;
  vertData[2].normal      = normal;
  vertData[2].fTU         = TU3;
  vertData[2].fTV         = TV3;

  vertData[3].position    = V4;
  vertData[3].color       = Color4;
  vertData[3].normal      = normal;
  vertData[3].fTU         = TU4;
  vertData[3].fTV         = TV4;

  m_pd3dDevice->DrawPrimitiveUP(
                  D3DPT_TRIANGLESTRIP,
                  2,
                  &vertData,
                  sizeof( vertData[0] ) );
}



void LDApp::RenderTextureSection( const D3DXVECTOR3& V1,
                                  const D3DXVECTOR3& V2,
                                  const D3DXVECTOR3& V3,
                                  const D3DXVECTOR3& V4,
                                  const tTextureSection& TexSection,
                                  DWORD Color,
                                  DWORD Color2,
                                  DWORD Color3,
                                  DWORD Color4 )
{
  m_pd3dDevice->SetTexture( 0, TexSection.pTexture );

  float   TU[2][2] = { { TexSection.TU[0], TexSection.TU[0] }, { TexSection.TU[1], TexSection.TU[1] } },
          TV[2][2] = { { TexSection.TV[0], TexSection.TV[1] }, { TexSection.TV[0], TexSection.TV[1] } };


  if ( TexSection.Flags & tTextureSection::TSF_H_MIRROR )
  {
    std::swap( TU[0][0], TU[1][0] );
    std::swap( TU[0][1], TU[1][1] );
  }
  if ( TexSection.Flags & tTextureSection::TSF_V_MIRROR )
  {
    std::swap( TV[0][0], TV[0][1] );
    std::swap( TV[1][0], TV[1][1] );
  }

  if ( ( TexSection.Flags & tTextureSection::TSF_ROTATE_270 ) == tTextureSection::TSF_ROTATE_270 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[0][1];
    TV[0][0] = TV[0][1];
    TU[0][1] = TU[1][1];
    TV[0][1] = TV[1][1];
    TU[1][1] = TU[1][0];
    TV[1][1] = TV[1][0];
    TU[1][0] = TempTU;
    TV[1][0] = TempTV;
  }
  else if ( TexSection.Flags & tTextureSection::TSF_ROTATE_90 )
  {
    float   TempTU = TU[0][0];
    float   TempTV = TV[0][0];

    TU[0][0] = TU[1][0];
    TV[0][0] = TV[1][0];
    TU[1][0] = TU[1][1];
    TV[1][0] = TV[1][1];
    TU[1][1] = TU[0][1];
    TV[1][1] = TV[0][1];
    TU[0][1] = TempTU;
    TV[0][1] = TempTV;
  }
  else if ( TexSection.Flags & tTextureSection::TSF_ROTATE_180 )
  {
    std::swap( TU[0][0], TU[1][1] );
    std::swap( TV[0][0], TV[1][1] );
    std::swap( TU[1][0], TU[0][1] );
    std::swap( TV[1][0], TV[0][1] );
  }

  RenderQuad( V1, V2, V3, V4,
              TU[0][0], TV[0][0],
              TU[1][0], TV[1][0],
              TU[0][1], TV[0][1],
              TU[1][1], TV[1][1],
              Color, Color2, Color3, Color4 );
}



void LDApp::RenderQuad2d( int X, int Y, int Width, int Height,
                          float TU1, float TV1,
                          float TU2, float TV2,
                          float TU3, float TV3,
                          float TU4, float TV4,
                          DWORD Color,
                          DWORD Color2,
                          DWORD Color3,
                          DWORD Color4 )
{
  struct CUSTOMVERTEX
  {
      D3DXVECTOR3   position; // The position
      float         fRHW;
      D3DCOLOR      color;    // The color
      float         fTU,
                    fTV;
  };

  if ( Color2 == 0 )
  {
    Color4 = Color3 = Color2 = Color;
  }

  CUSTOMVERTEX          vertData[4];

  float   fDelta = -0.5f;

  float   fRHW = 1.0f;

  D3DXVECTOR3   ptPos( (float)X, (float)Y, 0.0f );
  D3DXVECTOR3   ptSize( (float)Width, (float)Height, 0.0f );

  m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 );

  vertData[0].position.x  = ptPos.x + fDelta;
  vertData[0].position.y  = ptPos.y + fDelta;
  vertData[0].position.z  = (float)ptPos.z;
  vertData[0].fRHW        = fRHW;
  vertData[0].color       = Color;
  vertData[0].fTU         = TU1;
  vertData[0].fTV         = TV1;

  vertData[1].position.x  = ptPos.x + ptSize.x + fDelta;
  vertData[1].position.y  = ptPos.y + fDelta;
  vertData[1].position.z  = (float)ptPos.z;
  vertData[1].fRHW        = fRHW;
  vertData[1].color       = Color2;
  vertData[1].fTU         = TU2;
  vertData[1].fTV         = TV2;

  vertData[2].position.x  = ptPos.x + fDelta;
  vertData[2].position.y  = ptPos.y + ptSize.y + fDelta;
  vertData[2].position.z  = (float)ptPos.z;
  vertData[2].fRHW        = fRHW;
  vertData[2].color       = Color3;
  vertData[2].fTU         = TU3;
  vertData[2].fTV         = TV3;

  vertData[3].position.x  = ptPos.x + ptSize.x + fDelta;
  vertData[3].position.y  = ptPos.y + ptSize.y + fDelta;
  vertData[3].position.z  = (float)ptPos.z;
  vertData[3].fRHW        = fRHW;
  vertData[3].color       = Color4;
  vertData[3].fTU         = TU4;
  vertData[3].fTV         = TV4;

  m_pd3dDevice->DrawPrimitiveUP(
                  D3DPT_TRIANGLESTRIP,
                  2,
                  &vertData,
                  sizeof( vertData[0] ) );
}




void LDApp::RenderQuad2d( int X, int Y, int Width, int Height,
                          DWORD Color,
                          DWORD Color2,
                          DWORD Color3,
                          DWORD Color4 )
{
  struct CUSTOMVERTEX
  {
      D3DXVECTOR3   position; // The position
      float         fRHW;
      D3DCOLOR      color;    // The color
  };

  if ( Color2 == 0 )
  {
    Color4 = Color3 = Color2 = Color;
  }

  CUSTOMVERTEX          vertData[4];

  float   fDelta = -0.5f;

  float   fRHW = 1.0f;

  D3DXVECTOR3   ptPos( (float)X, (float)Y, 0.0f );
  D3DXVECTOR3   ptSize( (float)Width, (float)Height, 0.0f );

  m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE );
  m_pd3dDevice->SetTexture( 0, NULL );

  vertData[0].position.x  = ptPos.x + fDelta;
  vertData[0].position.y  = ptPos.y + fDelta;
  vertData[0].position.z  = (float)ptPos.z;
  vertData[0].fRHW        = fRHW;
  vertData[0].color       = Color;

  vertData[1].position.x  = ptPos.x + ptSize.x + fDelta;
  vertData[1].position.y  = ptPos.y + fDelta;
  vertData[1].position.z  = (float)ptPos.z;
  vertData[1].fRHW        = fRHW;
  vertData[1].color       = Color2;

  vertData[2].position.x  = ptPos.x + fDelta;
  vertData[2].position.y  = ptPos.y + ptSize.y + fDelta;
  vertData[2].position.z  = (float)ptPos.z;
  vertData[2].fRHW        = fRHW;
  vertData[2].color       = Color3;

  vertData[3].position.x  = ptPos.x + ptSize.x + fDelta;
  vertData[3].position.y  = ptPos.y + ptSize.y + fDelta;
  vertData[3].position.z  = (float)ptPos.z;
  vertData[3].fRHW        = fRHW;
  vertData[3].color       = Color4;

  m_pd3dDevice->DrawPrimitiveUP(
                  D3DPT_TRIANGLESTRIP,
                  2,
                  &vertData,
                  sizeof( vertData[0] ) );
}




void LDApp::RenderQuadRotated2d( int X, int Y, int Width, int Height,
                                  float TU1, float TV1,
                                  float TU2, float TV2,
                                  float TU3, float TV3,
                                  float TU4, float TV4,
                                  float Angle,
                                  DWORD Color,
                                  DWORD Color2,
                                  DWORD Color3,
                                  DWORD Color4 )
{
  if ( Color2 == 0 )
  {
    Color4 = Color3 = Color2 = Color;
  }

  struct CUSTOMVERTEX
  {
    D3DXVECTOR3   vectPos;
    float         fRHW;
    DWORD         color;    // The color
    float         fTU,fTV;
  };

  CUSTOMVERTEX          vertData[4];


  m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 );

  vertData[0].fRHW        = 1.0f;
  vertData[0].color       = Color;
  vertData[0].fTU         = TU1;
  vertData[0].fTV         = TV1;

  vertData[1].fRHW        = 1.0f;
  vertData[1].color       = Color2;
  vertData[1].fTU         = TU2;
  vertData[1].fTV         = TV2;

  vertData[2].fRHW        = 1.0f;
  vertData[2].color       = Color3;
  vertData[2].fTU         = TU3;
  vertData[2].fTV         = TV3;

  vertData[3].fRHW        = 1.0f;
  vertData[3].color       = Color4;
  vertData[3].fTU         = TU4;
  vertData[3].fTV         = TV4;

  // this is wrong in so many ways...
  D3DXVECTOR3   vQuarter1( -Width * 0.5f, -Height * 0.5f, 0.0f );
  D3DXVECTOR3   vQuarter2(  Width * 0.5f, -Height * 0.5f, 0.0f );
  D3DXVECTOR3   vQuarter3( -Width * 0.5f,  Height * 0.5f, 0.0f );
  D3DXVECTOR3   vQuarter4(  Width * 0.5f,  Height * 0.5f, 0.0f );

  D3DXVECTOR3   vQuarterRot1;
  D3DXVECTOR3   vQuarterRot2;
  D3DXVECTOR3   vQuarterRot3;
  D3DXVECTOR3   vQuarterRot4;

  float     fRad = -3.1415926f * Angle / 180.0f;
  vQuarterRot1.x = vQuarter1.x * cos( fRad ) - vQuarter1.y * sin( fRad );
  vQuarterRot1.y = vQuarter1.x * sin( fRad ) + vQuarter1.y * cos( fRad );
  vQuarterRot1.z = 0.0f;
  vQuarterRot2.x = vQuarter2.x * cos( fRad ) - vQuarter2.y * sin( fRad );
  vQuarterRot2.y = vQuarter2.x * sin( fRad ) + vQuarter2.y * cos( fRad );
  vQuarterRot2.z = 0.0f;
  vQuarterRot3.x = vQuarter3.x * cos( fRad ) - vQuarter3.y * sin( fRad );
  vQuarterRot3.y = vQuarter3.x * sin( fRad ) + vQuarter3.y * cos( fRad );
  vQuarterRot3.z = 0.0f;
  vQuarterRot4.x = vQuarter4.x * cos( fRad ) - vQuarter4.y * sin( fRad );
  vQuarterRot4.y = vQuarter4.x * sin( fRad ) + vQuarter4.y * cos( fRad );
  vQuarterRot4.z = 0.0f;

  vertData[0].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot1;
  vertData[1].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot2;
  vertData[2].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot3;
  vertData[3].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot4;

  m_pd3dDevice->DrawPrimitiveUP(
                  D3DPT_TRIANGLESTRIP,
                  2,
                  &vertData,
                  sizeof( vertData[0] ) );
}



void LDApp::RenderQuadRotated2d( int X, int Y, int Width, int Height,
                                 float TU1, float TV1,
                                 float TU2, float TV2,
                                 float TU3, float TV3,
                                 float TU4, float TV4,
                                 float Angle,
                                 float ZoomFactor,
                                 DWORD Color,
                                 DWORD Color2,
                                 DWORD Color3,
                                 DWORD Color4 )
{
  if ( Color2 == 0 )
  {
    Color4 = Color3 = Color2 = Color;
  }

  struct CUSTOMVERTEX
  {
    D3DXVECTOR3   vectPos;
    float         fRHW;
    DWORD         color;    // The color
    float         fTU, fTV;
  };

  CUSTOMVERTEX          vertData[4];


  m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 );

  vertData[0].fRHW = 1.0f;
  vertData[0].color = Color;
  vertData[0].fTU = TU1;
  vertData[0].fTV = TV1;

  vertData[1].fRHW = 1.0f;
  vertData[1].color = Color2;
  vertData[1].fTU = TU2;
  vertData[1].fTV = TV2;

  vertData[2].fRHW = 1.0f;
  vertData[2].color = Color3;
  vertData[2].fTU = TU3;
  vertData[2].fTV = TV3;

  vertData[3].fRHW = 1.0f;
  vertData[3].color = Color4;
  vertData[3].fTU = TU4;
  vertData[3].fTV = TV4;

  // this is wrong in so many ways...
  D3DXVECTOR3   vQuarter1( -Width * 0.5f * ZoomFactor, -Height * 0.5f * ZoomFactor, 0.0f );
  D3DXVECTOR3   vQuarter2(  Width * 0.5f * ZoomFactor, -Height * 0.5f * ZoomFactor, 0.0f );
  D3DXVECTOR3   vQuarter3( -Width * 0.5f * ZoomFactor,  Height * 0.5f * ZoomFactor, 0.0f );
  D3DXVECTOR3   vQuarter4(  Width * 0.5f * ZoomFactor,  Height * 0.5f * ZoomFactor, 0.0f );

  D3DXVECTOR3   vQuarterRot1;
  D3DXVECTOR3   vQuarterRot2;
  D3DXVECTOR3   vQuarterRot3;
  D3DXVECTOR3   vQuarterRot4;

  float     fRad = -3.1415926f * Angle / 180.0f;
  vQuarterRot1.x = vQuarter1.x * cos( fRad ) - vQuarter1.y * sin( fRad );
  vQuarterRot1.y = vQuarter1.x * sin( fRad ) + vQuarter1.y * cos( fRad );
  vQuarterRot1.z = 0.0f;
  vQuarterRot2.x = vQuarter2.x * cos( fRad ) - vQuarter2.y * sin( fRad );
  vQuarterRot2.y = vQuarter2.x * sin( fRad ) + vQuarter2.y * cos( fRad );
  vQuarterRot2.z = 0.0f;
  vQuarterRot3.x = vQuarter3.x * cos( fRad ) - vQuarter3.y * sin( fRad );
  vQuarterRot3.y = vQuarter3.x * sin( fRad ) + vQuarter3.y * cos( fRad );
  vQuarterRot3.z = 0.0f;
  vQuarterRot4.x = vQuarter4.x * cos( fRad ) - vQuarter4.y * sin( fRad );
  vQuarterRot4.y = vQuarter4.x * sin( fRad ) + vQuarter4.y * cos( fRad );
  vQuarterRot4.z = 0.0f;

  vertData[0].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot1;
  vertData[1].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot2;
  vertData[2].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot3;
  vertData[3].vectPos = D3DXVECTOR3( (float)X, (float)Y, 0 ) + vQuarterRot4;

  m_pd3dDevice->DrawPrimitiveUP(
    D3DPT_TRIANGLESTRIP,
    2,
    &vertData,
    sizeof( vertData[0] ) );
}



IDirectSoundBuffer* LDApp::LoadWave( const char* szFileName )
{
  WAVEFORMATEX        wfDummy;

  DSBUFFERDESC1       dsBufferDesc;

  HRESULT             hResult;

  char                *pPointer1,
                      *pPointer2;

  unsigned char       ucBuffer[16];

  DWORD               dwChunkSize,
                      dwSize1,
                      dwSize2;

  if ( m_pDirectSound == NULL )
  {
    return NULL;
  }

  // Wave einlesen
  FILE*   fileSound = fopen( szFileName, "rb" );
  if ( fileSound == NULL )
  {
    return NULL;
  }

  fread( ucBuffer, 8, 1, fileSound );
  if ( ( ucBuffer[0] != 82 )
  &&   ( ucBuffer[1] != 73 )
  &&   ( ucBuffer[2] != 70 )
  &&   ( ucBuffer[3] != 70 ) )
  {
    // kein RIFF
    fclose( fileSound );
    return NULL;
  }
  fread( ucBuffer, 8, 1, fileSound );
  if ( ( ucBuffer[0] != 87 )
  &&   ( ucBuffer[1] != 65 )
  &&   ( ucBuffer[2] != 86 )
  &&   ( ucBuffer[3] != 69 )
  &&   ( ucBuffer[4] != 102 )
  &&   ( ucBuffer[5] != 109 )
  &&   ( ucBuffer[6] != 116 )
  &&   ( ucBuffer[7] != 32 ) )
  {
    // kein WAVEfmt_
    fclose( fileSound );
    return NULL;
  }
  fread( &dwChunkSize, 4, 1, fileSound );
  if ( dwChunkSize != 16 )
  {
    // Nicht Standardgröße, ich bin verwörrt
    fclose( fileSound );
    return NULL;
  }

  // Da ist jetzt das wichtige Zeugs drin
  fread( ucBuffer, 16, 1, fileSound );

  fseek( fileSound, dwChunkSize - 16, SEEK_CUR );

  // Set up wave format structure.
  memset( &wfDummy, 0, sizeof( WAVEFORMATEX ) );
  wfDummy.wFormatTag = WAVE_FORMAT_PCM;    // Immer
  wfDummy.nChannels = ucBuffer[2] + 256 * ucBuffer[3];
  wfDummy.nSamplesPerSec = ucBuffer[4] + 256 * ucBuffer[5] + 65536 * ucBuffer[6] + 16777217 * ucBuffer[7];
  wfDummy.nBlockAlign = ucBuffer[12] + 256 * ucBuffer[13];
  wfDummy.nAvgBytesPerSec = wfDummy.nSamplesPerSec * wfDummy.nBlockAlign;
  wfDummy.wBitsPerSample = ucBuffer[14] + 256 * ucBuffer[15];

  fread( ucBuffer, 4, 1, fileSound );
  if ( ( ucBuffer[0] != 100 )
  &&   ( ucBuffer[1] != 97 )
  &&   ( ucBuffer[2] != 116 )
  &&   ( ucBuffer[3] != 97 ) )
  {
    // kein data
    fclose( fileSound );
    return NULL;
  }
  fread( &dwChunkSize, 4, 1, fileSound );

  // DSBUFFERDESC1 füllen
  memset( &dsBufferDesc, 0, sizeof( DSBUFFERDESC1 ) );            // Zero it out.
  dsBufferDesc.dwSize = sizeof( DSBUFFERDESC1 );                  // Immer
  dsBufferDesc.dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
    //DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2;// | DSBCAPS_STICKYFOCUS;
  //  DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
  dsBufferDesc.dwBufferBytes = dwChunkSize;
  dsBufferDesc.lpwfxFormat = (LPWAVEFORMATEX)&wfDummy;

  // DirectSoundBuffer anlegen
  IDirectSoundBuffer*   pSoundBuffer = NULL;

  hResult = m_pDirectSound->CreateSoundBuffer( (LPDSBUFFERDESC)&dsBufferDesc,
                                               &pSoundBuffer,
                                               NULL );
  if ( hResult == DS_OK )
  {
    hResult = pSoundBuffer->Lock( 0, dwChunkSize, (void **)&pPointer1, (LPDWORD)&dwSize1, (void **)&pPointer2, (LPDWORD)&dwSize2, 0 );
    if ( hResult != DS_OK )
    {
      // Konnte Buffer nicht "locken"
      fclose( fileSound );
      pSoundBuffer->Release();
      return NULL;
    }
    fread( pPointer1, dwSize1, 1, fileSound );
    if ( ( dwSize2 != 0 )
    &&   ( pPointer2 != NULL ) )
    {
      // Zweiten Teil nur bei Wrap einladen
      fread( pPointer2, dwSize2, 1, fileSound );
    }
    else
    {
      dwSize2 = 0;
    }
    fclose( fileSound );
    hResult = pSoundBuffer->Unlock( pPointer1, dwSize1, pPointer2, dwSize2 );
    if ( hResult != DS_OK )
    {
      // Konnte Buffer nicht "unlocken"
      fclose( fileSound );
      pSoundBuffer->Release();
      return NULL;
    }
    fclose( fileSound );

    return pSoundBuffer;
  }
  // Failed
  fclose( fileSound );

  return NULL;

}



IDirect3DTexture8* LDApp::LoadTexture( const char* szFileName, DWORD ColorKey )
{

  IDirect3DTexture8*    pNewTexture = NULL;

  if ( ColorKey )
  {
    if ( FAILED( D3DXCreateTextureFromFileEx( m_pd3dDevice, szFileName,
                                              D3DX_DEFAULT, D3DX_DEFAULT,
                                              1,
                                              0,
                                              D3DFMT_UNKNOWN,
                                              D3DPOOL_MANAGED,
                                              D3DX_FILTER_NONE,
                                              D3DX_FILTER_NONE,
                                              ColorKey,
                                              NULL,
                                              NULL,
                                              &pNewTexture ) ) )
    {
      return NULL;
    }
    return pNewTexture;
  }


  if ( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, szFileName, &pNewTexture ) ) )
  {
    return NULL;
  }
  return pNewTexture;

}




void LDApp::UpdateFrame( const float ElapsedTime )
{
  Rotation += ElapsedTime;

  m_WavyTextTimeCount += 250.0f * ElapsedTime;

  float     timeToUse = ElapsedTime;
  while ( timeToUse > 0.0f )
  {
    if ( m_FixedFrameDelay + timeToUse > 0.02f )
    {
      float     timeSlice = 0.02f - m_FixedFrameDelay;
      timeToUse -= timeSlice;
      if ( m_pCurrentGameState )
      {
        m_pCurrentGameState->UpdateFrame( timeSlice );
        m_pCurrentGameState->UpdateFixed();
      }
      m_FixedFrameDelay = 0.0f;
    }
    else
    {
      m_FixedFrameDelay += timeToUse;
      m_pCurrentGameState->UpdateFrame( timeToUse );
      timeToUse = 0.0f;
    }
  }
}



void LDApp::NextState( GameState* pNewState )
{

  if ( pNewState )
  {
    m_pNextState = pNewState;
  }

}



void LDApp::Run()
{

  if ( FAILED( DirectSoundCreate( NULL, &m_pDirectSound, NULL ) ) )
  {
    MessageBox( NULL, "Couldn't create DirectSound object", "Error", 0 );
    return;
  }
  m_pd3d = Direct3DCreate8( D3D_SDK_VERSION );
  if ( m_pd3d == NULL )
  {
    MessageBox( NULL, "Couldn't create Direct3D8", "Error", 0 );
    return;
  }

  //m_FullScreen = ( MessageBox( NULL, "Do you want to run in fullscreen mode?", "LD#15: Caverns of Venus", MB_YESNO ) == IDYES );
  m_FullScreen = false;

  DWORD   dwStyles = WS_VISIBLE | WS_POPUP;
  RECT    rcWindow;

  SetRect( &rcWindow, 0, 0, 1024, 768 );
  if ( !m_FullScreen )
  {
    dwStyles |= WS_CAPTION | WS_SYSMENU | WS_DLGFRAME;
    AdjustWindowRect( &rcWindow, dwStyles, FALSE );

    OffsetRect( &rcWindow, rcWindow.left, rcWindow.top );
    OffsetRect( &rcWindow,
                ( GetSystemMetrics( SM_CXSCREEN ) - ( rcWindow.right - rcWindow.left ) ) / 2,
                ( GetSystemMetrics( SM_CYSCREEN ) - ( rcWindow.bottom - rcWindow.top ) ) / 2 );
  }

  m_hWnd = CreateWindow( "STATIC", "LD #42 - LOST - Running out of Space", dwStyles,
                         rcWindow.left, rcWindow.top,
                         rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
                         NULL, 0, GetModuleHandle( NULL ), 0 );

  SetWindowLongPtr( m_hWnd, GWL_WNDPROC, (LONG)(LONG_PTR)StaticWindowProc );

  SendMessage( m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)m_hIcon );
  SendMessage( m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hIcon );

  m_pDirectSound->SetCooperativeLevel( m_hWnd, DSSCL_EXCLUSIVE );

  m_d3dPP.BackBufferWidth   = 1024;
  m_d3dPP.BackBufferHeight  = 768;
  m_d3dPP.BackBufferFormat  = D3DFMT_R5G6B5;
  m_d3dPP.EnableAutoDepthStencil  = TRUE;
  // TODO - try different formats before failing!
  m_d3dPP.AutoDepthStencilFormat  = D3DFMT_D16;
  if ( !m_FullScreen )
  {
    m_d3dPP.Windowed          = TRUE;
    m_d3dPP.BackBufferCount   = 1;
    m_d3dPP.SwapEffect        = D3DSWAPEFFECT_FLIP;
    m_d3dPP.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  }
  else
  {
    m_d3dPP.Windowed          = FALSE;
    m_d3dPP.BackBufferCount   = 0;
    m_d3dPP.SwapEffect        = D3DSWAPEFFECT_DISCARD;
    m_d3dPP.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  }

  m_d3dPP.hDeviceWindow     = m_hWnd;

  if ( FAILED( m_pd3d->CreateDevice( D3DADAPTER_DEFAULT,
                                        D3DDEVTYPE_HAL,
                                        m_hWnd,
                                        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                        &m_d3dPP,
                                        &m_pd3dDevice ) ) )
  {
    // fall"back" to 32 bit if 16 bit won't work
    m_d3dPP.BackBufferFormat  = D3DFMT_X8R8G8B8;
    if ( FAILED( m_pd3d->CreateDevice( D3DADAPTER_DEFAULT,
                                          D3DDEVTYPE_HAL,
                                          m_hWnd,
                                          D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                          &m_d3dPP,
                                          &m_pd3dDevice ) ) )
    {
      // fall"back" to 24 bit if 16 bit won't work (crap card ahoy)
      m_d3dPP.BackBufferFormat  = D3DFMT_R8G8B8;
      if ( FAILED( m_pd3d->CreateDevice( D3DADAPTER_DEFAULT,
                                            D3DDEVTYPE_HAL,
                                            m_hWnd,
                                            D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                            &m_d3dPP,
                                            &m_pd3dDevice ) ) )
      {
        MessageBox( m_hWnd, "Cannot create D3D Device, tried R5G6B5, R8G8B8 and X8R8G8B8.", "Oh the noes!", 0 );
        DestroyWindow( m_hWnd );
        return;
      }
    }
  }

  LoadResources();

  m_Music.Initialize( m_hWnd );
  m_Music.SetVolume( 100 );

  m_Music.LoadMusic( "sounds/music.ogg" );
  m_Music.Play();

  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );

  CTimer::Time( CTimer::TF_GETELAPSEDTIME );

  m_pCurrentGameState = new GSMenu();
  //m_pCurrentGameState = new CGSGame();

  MSG   msg;

  while ( true )
  {
    if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
    {
      if ( !GetMessage( &msg, NULL, 0, 0 ) )
      {
        break;
      }
      TranslateMessage( &msg );
      DispatchMessage( &msg );
    }
    else
    {
      HRESULT   hRes = S_OK;

      if ( FAILED( hRes = m_pd3dDevice->TestCooperativeLevel() ) )
      {
        // If the device was lost, do not render until we get it back
        if ( D3DERR_DEVICELOST != hRes )
        {
          // Check if the device needs to be resized.
          if ( D3DERR_DEVICENOTRESET == hRes )
          {
            Unload3dResources();

            if ( SUCCEEDED( m_pd3dDevice->Reset( &m_d3dPP ) ) )
            {
              Load3dResources();
            }
          }
        }
      }
      else
      {
        // display loop. now WITH BeginScene/EndScene
        HRESULT   hRes = m_pd3dDevice->BeginScene();
        if ( SUCCEEDED( hRes ) )
        {
          RenderFrame();

          m_pd3dDevice->EndScene();

          hRes = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
        }
      }

      float   elapsedTime = ( GetTickCount() - m_LastTicks ) * 0.001f;

      m_LastTicks = GetTickCount();

      elapsedTime = CTimer::Time( CTimer::TF_GETELAPSEDTIME );

      UpdateFrame( elapsedTime );

      if ( m_pNextState )
      {
        delete m_pCurrentGameState;
        m_pCurrentGameState = m_pNextState;
        m_pNextState = NULL;
      }
    }
  }

  if ( m_pCurrentGameState )
  {
    delete m_pCurrentGameState;
  }

  UnloadResources();

  if ( m_pDirectSound != NULL )
  {
    m_pDirectSound->Release();
    m_pDirectSound = NULL;
  }

  if ( m_pd3dDevice )
  {
    m_pd3dDevice->Release();
  }
  if ( m_pd3d )
  {
    m_pd3d->Release();
  }

  DestroyWindow( m_hWnd );

}



void LDApp::LoadResources()
{
  m_pSound[LD::SOUND_SHOT]        = LoadWave( "sounds/shot.wav" );
  m_pSound[LD::SOUND_PLAYER_DIED] = LoadWave( "sounds/died.wav" );
  m_pSound[LD::SOUND_LOST_TILE]   = LoadWave( "sounds/losttile.wav" );
  m_pSound[LD::SOUND_WIN_TILE]    = LoadWave( "sounds/wintile.wav" );
  m_pSound[LD::SOUND_EXPLODE]     = LoadWave( "sounds/explode.wav" );
  m_pSound[LD::SOUND_COLLECT_EMERALD] = LoadWave( "sounds/collectemerald.wav" );
  m_pSound[LD::SOUND_SPAWN_UFO]   = LoadWave( "sounds/spawnufo.wav" );
  m_pSound[LD::SOUND_SHOT_HIT]    = LoadWave( "sounds/shothit.wav" );

  Load3dResources();
}



void LDApp::Load3dResources()
{
  m_pTextureUnits = LoadTexture( "images/units.png", 0xffff00ff );
  m_pTextureTiles = LoadTexture( "images/tiles.png" );
  m_pTextureFont  = LoadTexture( "images\\font.bmp", 0xff000000 );

  m_TexSec[LD::TEX_PLAYER_SHIP] = tTextureSection( m_pTextureUnits, 1, 1, 46, 46 );
  m_TexSec[LD::TEX_GRID_FILLED] = tTextureSection( m_pTextureTiles, 0, 0, 32, 32 );
  m_TexSec[LD::TEX_PLAYER_SHOT] = tTextureSection( m_pTextureUnits, 1, 116, 5, 5 );
  m_TexSec[LD::TEX_PARTICLE] = tTextureSection( m_pTextureUnits, 1, 97, 17, 17 );
  m_TexSec[LD::TEX_CLOUD] = tTextureSection( m_pTextureUnits, 0, 129, 32, 32 );
  m_TexSec[LD::TEX_EMERALD] = tTextureSection( m_pTextureUnits, 1, 49, 46, 46 );
  m_TexSec[LD::TEX_UFO_1] = tTextureSection( m_pTextureUnits, 48, 0, 48, 48 );
  m_TexSec[LD::TEX_UFO_2] = tTextureSection( m_pTextureUnits, 48 + 48, 0, 48, 48 );
  m_TexSec[LD::TEX_UFO_3] = tTextureSection( m_pTextureUnits, 48 + 96, 0, 48, 48 );
  m_TexSec[LD::TEX_FIRE_PARTICLE] = tTextureSection( m_pTextureUnits, 20, 97, 7, 7 );

  // Font info from Generator
  m_mapLetters[32] = tTextureSection( m_pTextureFont, 0, 0, 7, 33 );
  m_mapLetters[33] = tTextureSection( m_pTextureFont, 0, 33, 7, 33 );
  m_mapLetters[38] = tTextureSection( m_pTextureFont, 0, 66, 0, 33 );
  m_mapLetters[39] = tTextureSection( m_pTextureFont, 0, 66, 6, 33 );
  m_mapLetters[44] = tTextureSection( m_pTextureFont, 0, 99, 6, 33 );
  m_mapLetters[46] = tTextureSection( m_pTextureFont, 0, 132, 6, 33 );
  m_mapLetters[58] = tTextureSection( m_pTextureFont, 0, 165, 6, 33 );
  m_mapLetters[59] = tTextureSection( m_pTextureFont, 0, 198, 6, 33 );
  m_mapLetters[34] = tTextureSection( m_pTextureFont, 7, 0, 11, 33 );
  m_mapLetters[36] = tTextureSection( m_pTextureFont, 7, 33, 11, 33 );
  m_mapLetters[40] = tTextureSection( m_pTextureFont, 7, 66, 11, 33 );
  m_mapLetters[41] = tTextureSection( m_pTextureFont, 7, 99, 10, 33 );
  m_mapLetters[43] = tTextureSection( m_pTextureFont, 7, 132, 11, 33 );
  m_mapLetters[45] = tTextureSection( m_pTextureFont, 7, 165, 11, 33 );
  m_mapLetters[48] = tTextureSection( m_pTextureFont, 7, 198, 10, 33 );
  m_mapLetters[35] = tTextureSection( m_pTextureFont, 18, 0, 17, 33 );
  m_mapLetters[37] = tTextureSection( m_pTextureFont, 35, 0, 19, 33 );
  m_mapLetters[42] = tTextureSection( m_pTextureFont, 54, 0, 12, 33 );
  m_mapLetters[47] = tTextureSection( m_pTextureFont, 66, 0, 12, 33 );
  m_mapLetters[49] = tTextureSection( m_pTextureFont, 78, 0, 8, 33 );
  m_mapLetters[50] = tTextureSection( m_pTextureFont, 86, 0, 10, 33 );
  m_mapLetters[51] = tTextureSection( m_pTextureFont, 96, 0, 10, 33 );
  m_mapLetters[52] = tTextureSection( m_pTextureFont, 106, 0, 10, 33 );
  m_mapLetters[53] = tTextureSection( m_pTextureFont, 116, 0, 10, 33 );
  m_mapLetters[54] = tTextureSection( m_pTextureFont, 126, 0, 10, 33 );
  m_mapLetters[55] = tTextureSection( m_pTextureFont, 136, 0, 10, 33 );
  m_mapLetters[56] = tTextureSection( m_pTextureFont, 146, 0, 10, 33 );
  m_mapLetters[57] = tTextureSection( m_pTextureFont, 156, 0, 10, 33 );
  m_mapLetters[61] = tTextureSection( m_pTextureFont, 166, 0, 11, 33 );
  m_mapLetters[63] = tTextureSection( m_pTextureFont, 177, 0, 11, 33 );
  m_mapLetters[64] = tTextureSection( m_pTextureFont, 188, 0, 19, 33 );
  m_mapLetters[65] = tTextureSection( m_pTextureFont, 207, 0, 11, 33 );
  m_mapLetters[66] = tTextureSection( m_pTextureFont, 218, 0, 10, 33 );
  m_mapLetters[67] = tTextureSection( m_pTextureFont, 228, 0, 10, 33 );
  m_mapLetters[68] = tTextureSection( m_pTextureFont, 238, 0, 10, 33 );
  m_mapLetters[73] = tTextureSection( m_pTextureFont, 248, 0, 6, 33 );
  m_mapLetters[69] = tTextureSection( m_pTextureFont, 18, 33, 10, 33 );
  m_mapLetters[70] = tTextureSection( m_pTextureFont, 18, 66, 10, 33 );
  m_mapLetters[71] = tTextureSection( m_pTextureFont, 18, 99, 10, 33 );
  m_mapLetters[74] = tTextureSection( m_pTextureFont, 18, 132, 10, 33 );
  m_mapLetters[79] = tTextureSection( m_pTextureFont, 18, 165, 10, 33 );
  m_mapLetters[80] = tTextureSection( m_pTextureFont, 18, 198, 10, 33 );
  m_mapLetters[72] = tTextureSection( m_pTextureFont, 28, 33, 11, 33 );
  m_mapLetters[75] = tTextureSection( m_pTextureFont, 28, 66, 11, 33 );
  m_mapLetters[76] = tTextureSection( m_pTextureFont, 28, 99, 11, 33 );
  m_mapLetters[78] = tTextureSection( m_pTextureFont, 28, 132, 11, 33 );
  m_mapLetters[81] = tTextureSection( m_pTextureFont, 28, 165, 10, 33 );
  m_mapLetters[82] = tTextureSection( m_pTextureFont, 28, 198, 10, 33 );
  m_mapLetters[77] = tTextureSection( m_pTextureFont, 39, 33, 15, 33 );
  m_mapLetters[83] = tTextureSection( m_pTextureFont, 39, 66, 11, 33 );
  m_mapLetters[84] = tTextureSection( m_pTextureFont, 39, 99, 10, 33 );
  m_mapLetters[85] = tTextureSection( m_pTextureFont, 39, 132, 10, 33 );
  m_mapLetters[86] = tTextureSection( m_pTextureFont, 39, 165, 11, 33 );
  m_mapLetters[87] = tTextureSection( m_pTextureFont, 39, 198, 14, 33 );
  m_mapLetters[88] = tTextureSection( m_pTextureFont, 54, 33, 12, 33 );
  m_mapLetters[89] = tTextureSection( m_pTextureFont, 66, 33, 10, 33 );
  m_mapLetters[90] = tTextureSection( m_pTextureFont, 76, 33, 10, 33 );
  m_mapLetters[91] = tTextureSection( m_pTextureFont, 86, 33, 10, 33 );
  m_mapLetters[92] = tTextureSection( m_pTextureFont, 96, 33, 15, 33 );
  m_mapLetters[93] = tTextureSection( m_pTextureFont, 111, 33, 10, 33 );
  m_mapLetters[95] = tTextureSection( m_pTextureFont, 121, 33, 10, 33 );
  m_mapLetters[97] = tTextureSection( m_pTextureFont, 131, 33, 11, 33 );
  m_mapLetters[98] = tTextureSection( m_pTextureFont, 142, 33, 10, 33 );
  m_mapLetters[99] = tTextureSection( m_pTextureFont, 152, 33, 10, 33 );
  m_mapLetters[100] = tTextureSection( m_pTextureFont, 162, 33, 10, 33 );
  m_mapLetters[101] = tTextureSection( m_pTextureFont, 172, 33, 10, 33 );
  m_mapLetters[102] = tTextureSection( m_pTextureFont, 182, 33, 10, 33 );
  m_mapLetters[103] = tTextureSection( m_pTextureFont, 192, 33, 10, 33 );
  m_mapLetters[104] = tTextureSection( m_pTextureFont, 202, 33, 11, 33 );
  m_mapLetters[105] = tTextureSection( m_pTextureFont, 213, 33, 6, 33 );
  m_mapLetters[106] = tTextureSection( m_pTextureFont, 219, 33, 10, 33 );
  m_mapLetters[107] = tTextureSection( m_pTextureFont, 229, 33, 11, 33 );
  m_mapLetters[108] = tTextureSection( m_pTextureFont, 240, 33, 11, 33 );
  m_mapLetters[109] = tTextureSection( m_pTextureFont, 54, 66, 15, 33 );
  m_mapLetters[110] = tTextureSection( m_pTextureFont, 54, 99, 11, 33 );
  m_mapLetters[111] = tTextureSection( m_pTextureFont, 54, 132, 10, 33 );
  m_mapLetters[112] = tTextureSection( m_pTextureFont, 54, 165, 10, 33 );
  m_mapLetters[113] = tTextureSection( m_pTextureFont, 54, 198, 10, 33 );
  m_mapLetters[114] = tTextureSection( m_pTextureFont, 69, 66, 10, 33 );
  m_mapLetters[116] = tTextureSection( m_pTextureFont, 69, 99, 10, 33 );
  m_mapLetters[117] = tTextureSection( m_pTextureFont, 69, 132, 10, 33 );
  m_mapLetters[121] = tTextureSection( m_pTextureFont, 69, 165, 10, 33 );
  m_mapLetters[122] = tTextureSection( m_pTextureFont, 69, 198, 10, 33 );
  m_mapLetters[115] = tTextureSection( m_pTextureFont, 79, 66, 11, 33 );
  m_mapLetters[118] = tTextureSection( m_pTextureFont, 79, 99, 11, 33 );
  m_mapLetters[119] = tTextureSection( m_pTextureFont, 90, 66, 14, 33 );
  m_mapLetters[120] = tTextureSection( m_pTextureFont, 104, 66, 12, 33 );

  HFONT   hTempFont = CreateFont( 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial" );
  D3DXCreateFont( m_pd3dDevice,
                  hTempFont,
                  &m_pFont );
  DeleteObject( hTempFont );


  Mesh    cube;

  cube.AddQuad( 0.0f, 3.0f, 0.0f, 0xffffffff,
                10.0f, 3.0f, 0.0f, 0xffffff00,
                00.0f, 13.0f, 0.0f, 0xffff00ff,
                10.0f, 13.0f, 0.0f, 0xff00ffff );
  cube.AddQuad( 0.0f, 3.0f, -10.0f, 0xffffffff,
                10.0f, 3.0f, -10.0f, 0xffffff00,
                00.0f, 3.0f, 0.0f, 0xffff00ff,
                10.0f, 3.0f, 0.0f, 0xff00ffff );

  m_pTestVB = CreateVertexBuffer( cube );

  /*

  Vertex    triangles[6];

  triangles[0].Pos    = D3DXVECTOR3( 0.0f, 3.0f, 0.0f );
  triangles[0].Normal = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  triangles[1].Pos    = D3DXVECTOR3( 10.0f, 3.0f, 0.0f );
  triangles[1].Normal = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  triangles[2].Pos    = D3DXVECTOR3( 0.0f, 13.0f, 0.0f );
  triangles[2].Normal = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  triangles[2].Diffuse = 0xff00ff00;

  triangles[3].Pos    = D3DXVECTOR3( 0.0f, 3.0f, -10.0f );
  triangles[3].Normal = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
  triangles[4].Pos    = D3DXVECTOR3( 10.0f, 3.0f, -10.0f );
  triangles[4].Normal = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
  triangles[5].Pos    = D3DXVECTOR3( 0.0f, 3.0f, 0.0f );
  triangles[5].Normal = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
  triangles[5].Diffuse = 0xffff0000;

  m_pTestVB = CreateVertexBuffer( 2, sizeof( Vertex ), sizeof( triangles ), D3DPT_TRIANGLELIST, 0, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_NORMAL, D3DPOOL_MANAGED );
  m_pTestVB->SetData( &triangles );
  */

  /*
  std::set<CVertexBuffer*>::iterator   it( m_setVBs.begin() );
  while ( it != m_setVBs.end() )
  {
    CVertexBuffer *pVB = *it;

    pVB->Restore( m_pd3dDevice );
    it++;
  }*/
}



void LDApp::UnloadResources()
{
  for ( int i = 0; i < LD::SOUND_LAST_ENTRY; ++i )
  {
    if ( m_pSound[i] )
    {
      m_pSound[i]->Release();
    }
  }

  Unload3dResources();
}



void LDApp::Unload3dResources()
{
  if ( m_pFont )
  {
    m_pFont->Release();
    m_pFont = NULL;
  }
  if ( m_pTextureTiles )
  {
    m_pTextureTiles->Release();
    m_pTextureTiles = NULL;
  }
  if ( m_pTextureUnits )
  {
    m_pTextureUnits->Release();
    m_pTextureUnits = NULL;
  }
  if ( m_pTextureFX )
  {
    m_pTextureFX->Release();
    m_pTextureFX = NULL;
  }
  if ( m_pTextureFont )
  {
    m_pTextureFont->Release();
    m_pTextureFont = NULL;
  }
  m_mapLetters.clear();

  while ( !m_setVBs.empty() )
  {
    RemoveVertexBuffer( *m_setVBs.begin() );
  }
}



CVertexBuffer* LDApp::CreateVertexBuffer( Mesh& mesh )
{
  CVertexBuffer*    pBuffer = CreateVertexBuffer( mesh.VertexList.size() / 3, 
                                                  sizeof( Vertex ),
                                                  sizeof( Vertex ) * mesh.VertexList.size(),
                                                  D3DPT_TRIANGLELIST, 
                                                  0, 
                                                  D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_NORMAL | D3DFVF_TEX1, 
                                                  D3DPOOL_MANAGED );
  pBuffer->SetData( &mesh.VertexList[0] );

  return pBuffer;
}



CVertexBuffer* LDApp::CreateVertexBuffer( DWORD dwPrimitiveCount, DWORD dwPrimitiveSize, DWORD dwBufferSize, D3DPRIMITIVETYPE dwPrimitiveType, DWORD dwUsage, DWORD dwFVF, D3DPOOL d3dPool )
{
  if ( !m_pd3dDevice )
  {
    return NULL;
  }

  CVertexBuffer*   pDX8VB = NULL;

  pDX8VB = new( std::nothrow ) CVertexBuffer();
  if ( pDX8VB == NULL )
  {
    return NULL;
  }

  pDX8VB->m_dwPrimitiveSize = dwPrimitiveSize;
  pDX8VB->m_dwPrimitiveCount = dwPrimitiveCount;
  pDX8VB->m_dwCompleteBufferSize  = dwBufferSize;
  pDX8VB->m_d3dPrimType = dwPrimitiveType;
  pDX8VB->m_d3dPool               = d3dPool;
  pDX8VB->m_dwFVF                 = dwFVF;
  pDX8VB->m_dwUsage               = dwUsage;

  if ( !pDX8VB->CreateBuffers( m_pd3dDevice ) )
  {
    OutputDebugString( "uhoh cb" );
  }

  pDX8VB->m_pData = new( std::nothrow ) BYTE[dwBufferSize];
  if ( pDX8VB->m_pData == NULL )
  {
    delete pDX8VB;
    return NULL;
  }

  m_setVBs.insert( pDX8VB );

  return pDX8VB;
}



void LDApp::RemoveVertexBuffer( CVertexBuffer* pVB )
{
  if ( !pVB )
  {
    return;
  }
  std::set<CVertexBuffer*>::iterator   it( m_setVBs.find( pVB ) );
  if ( it != m_setVBs.end() )
  {
    m_setVBs.erase( it );
    delete pVB;
  }
}



void LDApp::PlaySound( LD::SoundTypes Sound )
{

  IDirectSoundBuffer*   pBuffer = m_pSound[Sound];

  DWORD   Status;

  if ( SUCCEEDED( pBuffer->GetStatus( &Status ) ) )
  {
    if ( ( Status & DSBSTATUS_PLAYING )
    ||   ( Status & DSBSTATUS_LOOPING ) )
    {
      pBuffer->Stop();
      pBuffer->SetCurrentPosition( 0 );
    }
  }

  pBuffer->SetCurrentPosition( 0 );
  pBuffer->Play( 0, 0, 0 );

}



void LDApp::LoopSound( LD::SoundTypes Sound )
{

  IDirectSoundBuffer*   pBuffer = m_pSound[Sound];

  DWORD   Status;

  if ( SUCCEEDED( pBuffer->GetStatus( &Status ) ) )
  {
    if ( ( Status & DSBSTATUS_PLAYING )
    ||   ( Status & DSBSTATUS_LOOPING ) )
    {
      pBuffer->Stop();
      pBuffer->SetCurrentPosition( 0 );
    }
  }

  pBuffer->Play( 0, 0, DSBPLAY_LOOPING );

}



void LDApp::StopSound( LD::SoundTypes Sound )
{

  IDirectSoundBuffer*   pBuffer = m_pSound[Sound];

  DWORD   Status;

  if ( SUCCEEDED( pBuffer->GetStatus( &Status ) ) )
  {
    if ( ( Status & DSBSTATUS_PLAYING )
    ||   ( Status & DSBSTATUS_LOOPING ) )
    {
      pBuffer->Stop();
    }
  }

}



void LDApp::RenderButton( int X, int Y, int W, int H, LD::TextureTypes Tex1, LD::TextureTypes Tex2, LD::TextureTypes Tex3 )
{

  if ( ( m_MouseX >= X )
  &&   ( m_MouseX < X + W )
  &&   ( m_MouseY >= Y )
  &&   ( m_MouseY < Y + H ) )
  {
    if ( m_MouseButtons & 1 )
    {
      theApp.RenderTextureSection2d( X, Y, theApp.m_TexSec[Tex3] );
    }
    else
    {
      theApp.RenderTextureSection2d( X, Y, theApp.m_TexSec[Tex2] );
    }
  }
  else
  {
    theApp.RenderTextureSection2d( X, Y, theApp.m_TexSec[Tex1] );
  }

}



int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{

  theApp.Run();

  return 0;

}