/*
 Libs:
 -lopengl32
 -lglu32 
 -lgdi32
 -lwinmm
 -mwindows
 -loleaut32
 -luuid
*/

/**************************
 * Includes
 *
 **************************/

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glext.h>
#include "wglext.h"// https://khronos.org/registry/OpenGL/api/GL/wglext.h

#include <olectl.h>// Заголовочный файл для библиотеки
                   // управляющих элементов OLE (используется в BuildTexture)

#include "resource.h"

/**************************
 * Function Declarations
 *
 **************************/

float bgAngle=0.0f;
float pLoad=150.0f;
float loadAngleStep=1.0f;
float loadAngle=0.0f-pLoad*loadAngleStep;
float loadFarStep=0.1f;
float loadFar=-pLoad*loadFarStep;
  int pC=0;
  int sndVol=0, melVol=0;
  int qC=0, qCmx=4;
 bool rvOn=false;
float rvSteps=255.0f/2.5f;
float rvC, rvAngle, rvWidth, rvWstep, rvWmx=0.5f;
  int rvX, rvY, rvSide;
  int turn=1;
  int moveOff=0;

  int cx, cy;
  int posX=0, posY=0, posHL=1;
  int posXl=-1, posYl=-1;
  int mXar0 [10], mYar0 [10];
  int mXar1 [10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, mYar1 [10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  int mXar [10], mYar [10];
  int cCPU=2, cPlayer=2, cMove;
  int button=0;
float colorCoordHL [4]={0.0f, 0.0f, 0.0f}, colorCoordX [4]={0.0f, 0.0f, 1.0f}, colorCoordY [4]={1.0f, 1.0f, 1.0f},
      colorCellHL1 [4]={0.5f, 0.25f, 1.0f}, colorCellHL0 [4]={1.0f, 0.0f, 0.0f},
      colorCellOff [4]={1.0f, 0.8f, 0.1f},
      colorPlayer [4]={0.0f, 1.0f, 0.0f}, colorCPU [4]={0.35f, 0.35f, 0.35f},
      colorPlayerStat [4]={0.0f, 0.5f, 0.0f}, colorCPUStat [4]={0.35f, 0.35f, 0.35f},
      colorVol [4]={0.95f, 0.8f, 0.1f}, colorExitT [4]={0.85f, 0.0f, 0.0f},
      colorExitB [4]={1.0, 0.0f, 0.0f}, colorRestB [4]={1.0f, 0.85f, 0.15f},
      colorTxt [4]={1.0f, 1.0f, 1.0f}, colorTxtB [4]={0.5f, 0.5f, 0.5f}, colorH [4]={1.0f, 0.5f, 0.0f},
      colorShadow [4]={0.1f, 0.1f, 0.1f};
 char mCPUd [100] [65];
  int mCPUx [100], mCPUy [100], mCPUr [100], mCPUr0 [100];
  int AI=1;
  char txt [16];

float resultAngle;
 bool resultOff;

  int fpsOn=0;
 bool clockTweak=false;
 long clockL=0;
float clockD=0.0f;

 bool noRest=false, blur_on=false, loaded=false;
 bool moreFPS=true;
 bool bQuit=false;
 bool quitCPU=false;
 bool infOn=false;

 bool ctrl_key=false, keyLockEsc=false, keyLockEnter=false;
 int fontS, fps=-1, paintC=0, timeS=0;

  int dmW [96], dmH [96], dmB [96], dmC=0,
      dmH0, dmW0, dmB0, dmN=0,
      dmHs, dmWs, dmBs, dmHt, dmWt, dmBt;
 bool dmBitsOff=true;

GLuint texture [25];
GLuint base; // База списка отображения для фонта
GLuint PixelFormat;

COLORREF bGround=RGB (0, 0, 0);
HFONT font;// Идентификатор фонта
GLYPHMETRICSFLOAT gmf [256];// Массив с информацией о нашем шрифте
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

const unsigned int TIMER_MEL=5, TIMER_QUIT=10, TIMER_MELON=15;
COLORREF pixel=RGB (0, 0, 0);
TRACKMOUSEEVENT tme;
POINT mypoint;
HCURSOR curArrow, curWait, curNew, curOff;
static HANDLE gThreadCPU=NULL;
DWORD wThreadCPU;
DWORD WINAPI threadCPU (LPVOID);
WNDCLASS wc;
HWND hWnd;
HINSTANCE gThisInstance; int gFunsterStil;
HDC hDC;
HGLRC hRC;        
MSG msg;
PAINTSTRUCT PaintStruct;

char mb [64];

// Make the class name into a global variable
char szClassName []="OpenGL App";
char title []="Repaint";

// board
char init_d [64]={
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,2,1,0,0,0,
0,0,0,1,2,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};

char init_p [64]={
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,2,1,0,0,0,
0,0,0,1,2,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};

char rv_d [64];

 void paint ();
 void mouseMove ();
 void mouseClick ();
  int getPos (int x, int y);
 void cellInfo ();
  int reverse (int x, int y, int side, int mode=0);
 void windowUp ();
 void moveCPU ();
 void playerMove ();
 bool isMove ();
 void turnOver ();

 void statusBar ();
 void fpsC ();
float fpsTweak ();
 void saveConf ();
 void loadConf ();
 void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC, GLuint pf);
 void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC);
 void InitGL ();
  int InitMultisample ();
 void LoadGLTextures ();
 void BuildFont ();
 void KillFont();
 void glPrint ();
 void BuildLists ();
 void getScr ();
 void screenSet ();
 void screenUp ();
 void keysOff ();
 void loading ();


 char AppDir [_MAX_PATH];
  int soundVol=0, meloVol=0;
 bool soundOn=false, meloIs=false, audioOnce=false;
#include "sound.h"
#include "melody.h"



/**************************
 * WinMain
 *
 **************************/

int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine,
                    int iCmdShow)
{
 int i;

 gThisInstance=hInstance;
 gFunsterStil=iCmdShow;

 char AppPath [_MAX_PATH];
 int ap_l=0;
 memset (AppPath, 0, _MAX_PATH);
 memset (AppDir, 0, _MAX_PATH);
 GetModuleFileName (NULL, AppPath, _MAX_PATH);
 for (i=_MAX_PATH-1; i>=0 && ap_l==0; i--)
 {
  if (AppPath [i]=='\\')
   ap_l=i+1;
 }

 memcpy (AppDir, AppPath, ap_l);

 memset (mb, 0, 64);

 // initialize random seed:
 srand (time (NULL));

 getScr ();
 loadConf ();
 screenSet ();

 // register window class
 wc.style=CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
 wc.lpfnWndProc=WndProc;
 wc.cbClsExtra=0;
 wc.cbWndExtra=0;
 wc.hInstance=hInstance;
 wc.hIcon=LoadIcon (hInstance, MAKEINTRESOURCE(ID_PIC));
 wc.hCursor=LoadCursor (hInstance, MAKEINTRESOURCE(ID_CUR));
 curArrow=LoadCursor (hInstance, MAKEINTRESOURCE(ID_CUR));
 curWait=LoadCursor (hInstance, MAKEINTRESOURCE(ID_CUW));
 curNew=LoadCursor (hInstance, MAKEINTRESOURCE(ID_NEW));
 curOff=LoadCursor (hInstance, MAKEINTRESOURCE(ID_OFF));
 wc.hbrBackground=(HBRUSH)CreateSolidBrush (bGround);
 wc.lpszMenuName=NULL;
 wc.lpszClassName=szClassName;
 RegisterClass (&wc);

 for (i=0; i<2; i++)
 {
  hWnd=CreateWindowEx (
   0,           // Extended possibilites for variation
   szClassName, // Classname
   title,       // Title Text
   WS_POPUP,    // No caption & borders
   0,           // Program decides the position
   0,           // where the window ends up on the screen
   cx+1,        // The programs width
   cy+1,        // and height in pixels
   HWND_DESKTOP,// The window is a child-window to desktop
   NULL,        // No menu
   hInstance,   // Program Instance handler
   NULL         // No Window Creation data
  );

  if (i==0)
  {
   EnableOpenGL (hWnd, &hDC, &hRC, 0);
   PixelFormat=InitMultisample ();
   if (PixelFormat==0)
    break;
   DestroyWindow (hWnd);
  }
  else
   EnableOpenGL (hWnd, &hDC, &hRC, PixelFormat);
 }

 ShowWindow (hWnd, iCmdShow);
 SetForegroundWindow (hWnd);// Слегка повысим приоритет
 SetFocus (hWnd);// Установить фокус клавиатуры на наше окно
 InitGL ();

 ShowCursor (false);

 playSound ("board", 0, 1);

 tme.cbSize=sizeof(tme);
 tme.dwFlags=TME_HOVER;
 tme.hwndTrack=hWnd;// hanlde of window you want the mouse over message for.
 tme.dwHoverTime=HOVER_DEFAULT;

 TrackMouseEvent(&tme);

 gThreadCPU=CreateThread (NULL, 0, threadCPU, (void *)"threadCPU", 0, &wThreadCPU);

 loaded=true;

 // program main loop
 while (!bQuit)
 {
  // check for messages
  if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  {
   // handle or dispatch messages
   if (msg.message==WM_QUIT)
    bQuit=true;
   else
   {
    TranslateMessage (&msg);
    DispatchMessage (&msg);
   }
  }

  if (!bQuit)
  {
   if (!blur_on)
    paint ();
  }

  Sleep ((audioOnce ? 12 : 10)*(moreFPS ? 1 : 3));
 }

 saveConf ();
 meloClose ();

 quitCPU=true;
 for (int i=0; i<10 && quitCPU; i++)
  Sleep (10);
 CloseHandle (gThreadCPU);

 KillFont ();// Удаление шрифта

 // shutdown OpenGL
 DisableOpenGL (hWnd, hDC, hRC);

 ChangeDisplaySettings (NULL, 0);// Переключаемся обратно в оконный режим
 if (hRC)// Существует ли Контекст Рендеринга?
 {
  wglMakeCurrent (NULL, NULL);
  wglDeleteContext (hRC);
 }
 ReleaseDC (hWnd, hDC);// Возможно ли уничтожить DC?
 UnregisterClass (szClassName, gThisInstance);

 // destroy the window explicitly
 DestroyWindow (hWnd);

 return msg.wParam;
}

/********************
 * Window Procedure
 *
 ********************/

LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch (message)
 {
  case WM_CLOSE:
   PostQuitMessage (0);
   return 0;

  case WM_DESTROY:
   return 0;

  case WM_KILLFOCUS:
   keysOff ();

   meloBlurOn=true;
   blur_on=true;
   break;

  case WM_SETFOCUS:
   if (noRest==true || loaded==false)
    break;

   fpsOn=0;
   clockL=0;

   screenSet ();
   if (cx!=dmW0 || cy!=dmH0)
   {
    getScr ();
    dmN=0;
    dmWs=dmW0;
    dmHs=dmH0;
    dmBs=dmB0;
    screenUp ();
   }
   else
    windowUp ();

   meloBlurOff=true;
   blur_on=false;
   break;

  case WM_SIZE:
   switch (wParam)
   {
    case SIZE_RESTORED:
     if (blur_on)
      break;

     if (noRest==true || loaded==false)
      break;

     screenSet ();
     if (cx!=dmW0 || cy!=dmH0)
     {
      getScr ();
      dmN=0;
      dmWs=dmW0;
      dmHs=dmH0;
      dmBs=dmB0;
      screenUp ();
     }
     else
      windowUp ();

     break;
   }
   break;

  case WM_PAINT:
   BeginPaint(hWnd, &PaintStruct);
   if (blur_on && loaded)
   {
    hDC=GetDC (hWnd);
    paint ();
    ReleaseDC (hWnd, hDC);
   }
   EndPaint (hWnd, &PaintStruct);
   break;

  case WM_LBUTTONUP:
   mouseClick ();
   break;

  case WM_MOUSEMOVE:
   mouseMove ();
   break;


  case WM_TIMER:
   switch (wParam)
   {
    case TIMER_MELON:
     KillTimer (hWnd, TIMER_MELON);
     meloVol=melVol*250;
     break;
    case TIMER_MEL:
     KillTimer (hWnd, TIMER_MEL);
     meloInit ();
     break;
    case TIMER_QUIT:
     qC++;
     if (qC==qCmx)
     {
      KillTimer (hWnd, TIMER_QUIT);
      bQuit=true;
     }
     break;
   }
   break;

  case WM_KEYDOWN:
   switch (wParam)
   {
    case 81:
     if (ctrl_key)
      PostQuitMessage(0);
     break;

    case VK_ESCAPE:
     if (keyLockEsc)
      break;

     keyLockEsc=true;

     if (infOn)
     {
      infOn=false;
      playSound ("shake");
      mouseMove ();
     }
     break;

    case VK_RIGHT:
     if (posX<7)
     {
      posX++;
      cellInfo ();
     }
     break;

    case VK_LEFT:
     if (posX>0)
     {
      posX--;
      cellInfo ();
     }
     break;

    case VK_NEXT:
     if (posX<7 && posY<7)
     {
      posX++;
      posY++;
      cellInfo ();
     }
     break;

    case VK_PRIOR:
     if (posX<7 && posY>0)
     {
      posX++;
      posY--;
      cellInfo ();
     }
     break;

    case VK_UP:
     if (posY>0)
     {
      posY--;
      cellInfo ();
     }
     break;

    case VK_DOWN:
     if (posY<7)
     {
      posY++;
      cellInfo ();
     }
     break;

    case VK_HOME:
     if (posX>0 && posY>0)
     {
      posX--;
      posY--;
      cellInfo ();
     }
     break;

    case VK_END:
     if (posX>0 && posY<7)
     {
      posX--;
      posY++;
      cellInfo ();
     }
     break;

    case VK_CONTROL:
     ctrl_key=true;
     break;
   }

   if (wParam==VK_RETURN || wParam==VK_SPACE || wParam==VK_CLEAR)
   {
    if (keyLockEnter)
     break;

    playerMove ();
    keyLockEnter=true;
   }
   return 0;

  case WM_KEYUP:

   switch (wParam)
   {
    case VK_ESCAPE:
     keyLockEsc=false;
     break;

    case VK_CONTROL:
     ctrl_key=false;
     break;
   }

   if (wParam==VK_RETURN || wParam==VK_SPACE || wParam==VK_CLEAR)
    keyLockEnter=false;

   return 0;

  default:
   return DefWindowProc (hWnd, message, wParam, lParam);
 }
}

DWORD WINAPI threadCPU (LPVOID)
{
 // initialize random seed:
 srand (time (NULL));

 while (!quitCPU)
 {
  if (turn==2)
  {
   turn=3;
   moveCPU ();
  }

  Sleep (10);
 }

 quitCPU=false;
}

bool arCur=false;
void moveCPU ()
{
 int xi, yi, xm, ym, r, r0, mx, mx0, mx1=-100, n=0, i, c=0;
 int rs1, rs2;
 int tCPUr0 [100], tCPUx [100], tCPUy [100];
 bool found=false;

 for (yi=0; yi<8; yi++)
 {
  for (xi=0; xi<8; xi++)
  {
   memcpy (rv_d, init_d, 64);
   r=reverse (xi, yi, 2, 2);
   r0=r;
   if (r>0)
   {
    rs1=0; rs2=0;
    if (xi==0 || xi==7)
     rs1=1;
    if (yi==0 || yi==7)
     rs2=1;
    if (rs1+rs2==1)
     r+=5;
    else if (rs1+rs2==2)
     r+=25;

    mCPUr [n]=r;
    mCPUr0 [n]=r0;
    mCPUx [n]=xi;
    mCPUy [n]=yi;
    if (AI==1)
    {
     if (r>mx1)
      mx1=r;
    }
    else if (AI==2)
    {
     rv_d [getPos (xi, yi)]=2;
     memcpy (mCPUd [n], rv_d, 64);
    }
    n++;
   }
  }
 }

 if (AI==2)
 {
  for (i=0; i<n; i++)
  {
   mx=0;
   for (yi=0; yi<8; yi++)
   {
    for (xi=0; xi<8; xi++)
    {
     memcpy (rv_d, mCPUd [i], 64);
     r=reverse (xi, yi, 1);
     if (r>0)
     {
      rs1=0; rs2=0;
      if (xi==0 || xi==7)
       rs1=1;
      if (yi==0 || yi==7)
       rs2=1;
      if (rs1+rs2==1)
       r+=5;
      else if (rs1+rs2==2)
       r+=25;
     }

     if (r>mx)
      mx=r;
    }
   }

   mCPUr [i]-=mx;
   if (mCPUr [i]>mx1)
    mx1=mCPUr [i];
  }
 }

 for (i=0; i<n; i++)
 {
  if (mCPUr [i]==mx1 || AI==0)
  {
   found=true;
   tCPUr0 [c]=mCPUr0 [i];
   tCPUx [c]=mCPUx [i];
   tCPUy [c]=mCPUy [i];
   c++;
  }
 }

 if (found)
 {
  n=rand ()%c;
  mx0=tCPUr0 [n];
  xm=tCPUx [n];
  ym=tCPUy [n];

  moveOff=0;
  memcpy (rv_d, init_d, 64);
  reverse (xm, ym, 2, 1);
  memcpy (init_d, rv_d, 64);
  init_d [getPos (xm, ym)]=2;
  rvC=0.0f;
  rvX=xm;
  rvY=ym;
  rvSide=2;
  rvAngle=0.0f;
  rvWidth=0.0f;
  rvWstep=rvWmx*2.0f/rvSteps;
  rvOn=true;
  cCPU+=mx0+1;
  cPlayer-=mx0;
  char t [16];
  sprintf (t, "move%d", (rand ()%5+1));
  playSound (t);
 }
 else
 {
  moveOff++;
  if (moveOff==2 || cPlayer+cCPU==64 || !isMove ())
   turnOver ();
  else
  {
   turn=1;
   arCur=true;
   playSound ("break");
  }
 }
}

bool isMove ()
{
 int xi, yi, r;

 for (yi=0; yi<8; yi++)
 {
  for (xi=0; xi<8; xi++)
  {
   memcpy (rv_d, init_d, 64);
   r=reverse (xi, yi, 1);
   if (r>0)
    return true;
  }
 }

 return false;
}

bool toCur=false;
void turnOver ()
{
 resultAngle=90.0f;
 resultOff=false;
 turn=4;
 toCur=true;
}

void keysOff ()
{
 ctrl_key=false;
 keyLockEsc=false;
 keyLockEnter=false;
}

void getScr ()
{
 int i, i2, bitsN=0;
 bool dmRepeat;

 DEVMODE devMode;// Режим устройства
 memset (&devMode, 0, sizeof (devMode));// Очистка для хранения установок
 devMode.dmSize=sizeof (devMode);// Размер структуры Devmode

 for (i=0; EnumDisplaySettings (0, i, &devMode); i++)
 {
  dmRepeat=false;
  for (i2=0; i2<dmC; i2++)
  {
   if (dmW [i2]==devMode.dmPelsWidth && dmH [i2]==devMode.dmPelsHeight && dmB [i2]==devMode.dmBitsPerPel)
    dmRepeat=true;
  }
  if (!dmRepeat)
  {
   if (bitsN==0)
    bitsN=devMode.dmBitsPerPel;
   else if (bitsN!=devMode.dmBitsPerPel)
    dmBitsOff=false;

   dmW [dmC]=devMode.dmPelsWidth;
   dmH [dmC]=devMode.dmPelsHeight;
   dmB [dmC]=devMode.dmBitsPerPel;
   dmC++;
  }
 }

 int swpH, swpW, swpB;
 for (i=0; i<dmC; i++)
 {
  for (i2=i; i2<dmC; i2++)
  {
   if (dmW [i2]>dmW [i] || (dmW [i2]==dmW [i] && dmH [i2]>dmH [i])
   || (dmW [i2]==dmW [i] && dmH [i2]==dmH [i] && dmB [i2]>dmB [i]))
   {
    swpW=dmW [i];
    swpH=dmH [i];
    swpB=dmB [i];

    dmW [i]=dmW [i2];
    dmH [i]=dmH [i2];
    dmB [i]=dmB [i2];

    dmW [i2]=swpW;
    dmH [i2]=swpH;
    dmB [i2]=swpB;
   }
  }
 }

 memset (&devMode, 0, sizeof (devMode));// Очистка для хранения установок
 devMode.dmSize=sizeof (devMode);// Размер структуры Devmode
 EnumDisplaySettings (0, ENUM_CURRENT_SETTINGS, &devMode);
 dmW0=devMode.dmPelsWidth;
 dmH0=devMode.dmPelsHeight;
 dmB0=devMode.dmBitsPerPel;
}

void windowUp ()
{
 SetWindowPos (hWnd, HWND_TOP, 0, 0, cx+1, cy+1, SWP_NOMOVE);// ?
}

void screenSet ()
{
 cx=(LONG)::GetSystemMetrics (SM_CXSCREEN);
 cy=(LONG)::GetSystemMetrics (SM_CYSCREEN);
}

void screenUp ()
{
 noRest=true;

 windowUp ();

 // shutdown OpenGL
 DisableOpenGL (hWnd, hDC, hRC);
 EnableOpenGL (hWnd, &hDC, &hRC, PixelFormat);

 SetForegroundWindow (hWnd);// Слегка повысим приоритет
 SetFocus (hWnd);// Установить фокус клавиатуры на наше окно

 InitGL ();

 pC=0;

 noRest=false;
}

void InitGL ()
{
 glShadeModel (GL_SMOOTH);// Разрешить плавное затенение
 glViewport (0, 0, cx+2, cy+2);
 glMatrixMode (GL_PROJECTION);
 gluPerspective (45.0f, (GLfloat)cx/(GLfloat)cy, 0.1f, 100.0f);

 glClearDepth (1.0);      // Depth Buffer Setup
 glEnable (GL_DEPTH_TEST);// Enables Depth Testing
 glDepthFunc (GL_LEQUAL); // The Type Of Depth Testing To Do

 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
 glMatrixMode (GL_MODELVIEW);

 BuildFont ();// Построить шрифт

 if (PixelFormat!=0)
  glEnable (GL_MULTISAMPLE_ARB);

 loading ();
 LoadGLTextures ();
 glEnable (GL_TEXTURE_2D);

 int i;
 for (i=0; i<9; i++)
  mXar0 [i]=cx/2-(float)cy*4.5f/9.0f+cy*i/9;
 for (i=0; i<9; i++)
  mYar0 [i]=cy*(i+1)/9;

 // Функция смешивания для непрозрачности, базирующаяся на значении альфы
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

 glPolygonMode (GL_BACK, GL_LINE); // нижняя (задняя) сторона прорисована линиями
 glPolygonMode (GL_FRONT, GL_FILL);// верхняя (передняя) сторона заполнена

 BuildLists ();// создаем список отображения
}

/*******************
 * Enable OpenGL
 *
 *******************/

void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC, GLuint pf)
{
 PIXELFORMATDESCRIPTOR pfd;
 int iFormat;

 // get the device context (DC)
 *hDC=GetDC (hWnd);

 if (pf==0)
 {
  // set the pixel format for the DC
  ZeroMemory (&pfd, sizeof (pfd));
  pfd.nSize=sizeof (pfd);
  pfd.nVersion=1;
  pfd.dwFlags=PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  pfd.iPixelType=PFD_TYPE_RGBA;
  pfd.cColorBits=dmBs;
  pfd.cDepthBits=24;
  pfd.iLayerType=PFD_MAIN_PLANE;
  iFormat=ChoosePixelFormat (*hDC, &pfd);
  SetPixelFormat (*hDC, iFormat, &pfd);
 }
 else
  SetPixelFormat(*hDC, pf, &pfd);

 // create and enable the render context (RC)
 *hRC=wglCreateContext (*hDC);
 wglMakeCurrent (*hDC, *hRC);
}


/******************
 * Disable OpenGL
 *
 ******************/

void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC)
{
 KillFont ();// Удаление шрифта
 wglMakeCurrent (NULL, NULL);
 wglDeleteContext (hRC);
 ReleaseDC (hWnd, hDC);
}

// читаем изображение и преобразуем его в текстуру
void LoadGLTextures ()
{
 HDC hdcTemp;                 // DC для растра
 HBITMAP hbmpTemp;            // иногда храним в ней растр
 IPicture *pPicture;          // интерфейс IPicture
 OLECHAR wszPath [MAX_PATH+1];// полный путь до картинки (WCHAR)
 long lWidth;                 // ширина в логических единицах
 long lHeight;                // высота в логических единицах
 long lWidthPixels;           // ширина в пикселях
 long lHeightPixels;          // высота в пикселях
 GLint glMaxTexDim ;          // максимальный размер текстуры

 char texs [25] [32]={"blank.gif", "sky.jpg", "gray.gif",
                      "border.gif", "bordertop.gif", "bordercorner.gif", "bordlight.gif", "bordlighttop.gif",
                      "sphere.gif", "exit.gif", "snd.gif", "tune.gif", "info.gif", "bg.jpg", "ai.gif",
                      "tooltip.jpg"
                     };
 char texd [16]={"data\\textures"};
 char txt [_MAX_PATH];
 int i2, xi, yi, cl, ri;

 for (i2=0; i2<16; i2++)
 {
  if (strlen (texs [i2]))
  {
   sprintf (txt, "%s%s\\%s", AppDir, texd, texs [i2]);

   MultiByteToWideChar (CP_ACP, 0, txt, -1, wszPath, MAX_PATH);// преобразуем к юникоду
   HRESULT hr=OleLoadPicturePath (wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture);

   if (!FAILED (hr)) // Если загрузка удачна
   {
    hdcTemp=CreateCompatibleDC (GetDC (0));// создать совместимый с устройством Windows контекст
    if (!hdcTemp)         // ну что, создали?
      pPicture->Release();// не-а… :( уменьшение счетчика ссылок на IPicture
    else
    {
     // получить максимально возможное разрешение изображения
     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &glMaxTexDim);

     pPicture->get_Width (&lWidth);  // получить ширину изображения
     lWidthPixels=MulDiv (lWidth, GetDeviceCaps (hdcTemp, LOGPIXELSX), 2540);
     pPicture->get_Height (&lHeight);// получить высоту изображения
     lHeightPixels=MulDiv (lHeight, GetDeviceCaps (hdcTemp, LOGPIXELSY), 2540);

     // преобразовать изображение к ближайшей степени двойки
     if (lWidthPixels<=glMaxTexDim)
      // если ширина изображения меньше либо равна максимально-допустимому пределу карточки
      lWidthPixels=1<<(int)floor((log ((double)lWidthPixels)/log (2.0f))+0.5f);
     else
      // иначе установить размер равный максимальной степени двойки,
      // которую поддерживает карточка
      lWidthPixels=glMaxTexDim;
     // то же самое повторяется для высоты
     if (lHeightPixels<=glMaxTexDim)
      lHeightPixels=1<<(int)floor ((log ((double)lHeightPixels)/log (2.0f))+0.5f);
     else
      lHeightPixels=glMaxTexDim;

     // создать временный растр
     BITMAPINFO  bi={0}; // нужный нам тип растра
     DWORD   *pBits=0;   // указатель на биты растра

     bi.bmiHeader.biSize=sizeof (BITMAPINFOHEADER);// размер структуры
     bi.bmiHeader.biBitCount=32;                   // 32 бита
     bi.bmiHeader.biWidth=lWidthPixels;            // ширина кратная степени двойки
     // Сделаем изображение расположенным вверх (положительное направление оси Y)
     bi.bmiHeader.biHeight=lHeightPixels;
     bi.bmiHeader.biCompression=BI_RGB;            // RGB формат
     bi.bmiHeader.biPlanes=1;                      // 1 битовая плоскость 

     // создавая растр, таким образом, мы можем установить глубину цвета,
     // а также получить прямой доступ к битам.
     hbmpTemp=CreateDIBSection (hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0);

     if (!hbmpTemp)        // создали?
     {                     // сам вижу что нет
      DeleteDC (hdcTemp);  // убить контекст устройства
      pPicture->Release ();// уменьшить счетчик количества интерфейсов IPicture
     }
     else
     {
      // есть растр!
      SelectObject (hdcTemp, hbmpTemp);// загрузить описатель временного растра
                                       // в описатель временного контекста устройства 
      // отрисовка IPicture в растр
      pPicture->Render (hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0);

      long i, n=lWidthPixels*lHeightPixels;
      // преобразовать из BGR в RGB формат и устанавливаем значение Alpha

      if (i2==8 || i2==9 || i2==10 || i2==11 || i2==12 || i2==14)
      {
       for (i=0; i<n; i++) // Цикл по всем пикселям
       {
        BYTE* pPixel=(BYTE*)(&pBits[i]);// берем текущий пиксель
        BYTE  temp=pPixel [0];          // сохраняем первый цвет в переменной
                                        // Temp (Синий)
        pPixel [0]=pPixel [2];          // ставим  Красный на место (в первую позицию)
        pPixel [2]=temp;                // ставим значение Temp в третий параметр (3rd)

        if (pPixel [2]>150)
        {
         pPixel [0]=0;
         pPixel [1]=0;
         pPixel [2]=0;
         pPixel [3]=0;                  // установить значение alpha =0
        }
        else
        {
         yi=i/lWidthPixels;
         xi=i-yi*lWidthPixels;
         ri=sqrt (pow ((lWidthPixels/2-xi), 2)+pow ((lHeightPixels/2-yi), 2));

         cl=abs (lWidthPixels/2-ri);

         if (cl<12)
          cl=cl*cl;
         else
          cl=cl*16;
         if (cl>255)
          cl=255;
         pPixel [3]=cl;                // установить значение alpha
        }
       }
      }
      else
      {
       for (i=0; i<n; i++)// Цикл по всем пикселям
       {
        BYTE* pPixel=(BYTE*)(&pBits[i]);// берем текущий пиксель
        BYTE  temp=pPixel [0];          // сохраняем первый цвет в переменной
                                        // Temp (Синий)
        pPixel [0]=pPixel [2];          // ставим  Красный на место (в первую позицию)
        pPixel [2]=temp;                // ставим значение Temp в третий параметр (3rd)
        pPixel [3]=255;                 // установить значение alpha =255
       }
      }

      glGenTextures (1, &texture [i2]);//  создаем текстуру texid

      // типичная генерация текстуры, используя данные из растра
      glBindTexture (GL_TEXTURE_2D, texture [i2]);// делаем привязку к texid

      if (i2==0 || i2==2 || i2==3 || i2==4 || i2==5 || i2==15)
      {
       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      }

      // (измените для нужного вам типа фильтрации)
      glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//GL_NEAREST
      // (измените, если хотите использовать мипмап-фильтрацию) 
      glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

      // (мипмап - множественное отображение (последовательность текстур одного
      //  и того же изображения с уменьшающимся разрешением по мере удаления отображаемого
      // объекта от наблюдателя))

      glTexImage2D (GL_TEXTURE_2D, 0, 4, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits);

      DeleteObject (hbmpTemp);// удаляем объект
      DeleteDC (hdcTemp);     // удаляем контекст устройства

      pPicture->Release();    //уменьшает счетчик IPicture
     }
    }
   }
  }
 }
}

int InitMultisample()
{
 // Get Our Pixel Format
 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
 wglChoosePixelFormatARB=(PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress ("wglChoosePixelFormatARB");
 if (!wglChoosePixelFormatARB)
  return 0;

 HDC hDC=GetDC(hWnd);
 int pixelFormat;
 UINT numFormats;
 float fAttributes []={0, 0};

 // These Attributes Are The Bits We Want To Test For In Our Sample
 // Everything Is Pretty Standard, The Only One We Want To 
 // Really Focus On Is The SAMPLE BUFFERS ARB And WGL SAMPLES
 // These Two Are Going To Do The Main Testing For Whether Or Not
 // We Support Multisampling On This Hardware.
 int iAttributes[] = {
  WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
  WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
  WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
  WGL_COLOR_BITS_ARB, dmBs,
  WGL_ALPHA_BITS_ARB, 8,
  WGL_DEPTH_BITS_ARB, 24,
  WGL_STENCIL_BITS_ARB, 0,
  WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
  WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
  WGL_SAMPLES_ARB, 6,
  0, 0};

 // First We Check To See If We Can Get A Pixel Format For 6 Samples
 int r=wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);

 // If We Returned False, Or Our Format Count Is Less Than 1
 if (!(r && numFormats>=1))
 {
  // Our Pixel Format With 6 Samples Failed, Test For 4 Samples
  iAttributes [19]=4;
  r=wglChoosePixelFormatARB (hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
  if (!(r && numFormats>=1))
  {
   // Our Pixel Format With 4 Samples Failed, Test For 2 Samples
   iAttributes [19]=2;
   r=wglChoosePixelFormatARB (hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
   if (!(r && numFormats>=1))
 	return 0;
  }
 }    

 return pixelFormat;
}

void BuildFont ()// Построение нашего растрового шрифта
{
 base=glGenLists (256);// массив для 256 букв

 font=CreateFont (-fontS,                   // Высота фонта
                  0,                        // Ширина фонта
                  0,                        // Угол отношения
                  0,                        // Угол наклона
                  FW_BOLD,                  // Ширина шрифта
                  false,                    // Курсив
                  false,                    // Подчеркивание
                  false,                    // Перечеркивание
                  RUSSIAN_CHARSET,          // Идентификатор набора символов ANSI_CHARSET
                  OUT_TT_PRECIS,            // Точность вывода
                  CLIP_DEFAULT_PRECIS,      // Точность отсечения
                  ANTIALIASED_QUALITY,      // Качество вывода
                  FF_DONTCARE|DEFAULT_PITCH,// Семейство и шаг
                  "Courier New");           // Имя шрифта

 SelectObject (hDC, font);// Выбрать шрифт, созданный нами

 wglUseFontOutlines (hDC,        // Выбрать текущий контекст устройства (DC)
               0,                // Стартовый символ
               256,              // Количество создаваемых списков отображения
               base,             // Стартовое значение списка отображения
               0.0f,             // Отклонение от настоящего контура
               0.0f,             // Толщина шрифта по оси Z
               WGL_FONT_POLYGONS,// Использовать полигоны, а не линии WGL_FONT_LINES
               gmf);             // буфер адреса для данных списка отображения
}

void KillFont ()// Удаление шрифта
{
 glDeleteLists (base, 256); // Удаление всех 256 списков отображения
}

void glPrint (const char *fmt, ...)// Заказная функция «Печати» GL
{
 float length=0; // Переменная для нахождения физической длины текста
 char text [256];// Здесь наша строка
 va_list ap;     // Указатель на переменный список аргументов
 if (fmt==NULL)  // Если нет текста
  return;        // Ничего не делать

 va_start (ap, fmt);         // Анализ строки на переменные
 vsprintf (text, fmt, ap);   // И конвертация символов в реальные коды
 va_end (ap);                // Результат сохраняется в text

 for (int i=0; i<strlen (text); i++)// %
 {
  if (text [i]==17)
   text [i]=37;
 }

 for (unsigned int loop=0; loop<(strlen (text)); loop++)// Цикл поиска размера строки
  length+=gmf [(unsigned char)text [loop]].gmfCellIncX; // Увеличение размера на ширину символа
 glTranslatef (-length/2, 0.0f, 0.0f);                  // Центровка на экране нашей строки

 glPushAttrib (GL_LIST_BIT);    // Сохраняет в стеке значения битов списка отображения
 glListBase (base);             // Устанавливает базовый символ в 0

 // Создает списки отображения текста
 glCallLists (strlen (text), GL_UNSIGNED_BYTE, text);
 glPopAttrib ();// Восстанавливает значение Display List Bits

 glTranslatef (-length/2, 0.0f, 0.0f);// Центровка на экране нашей строки
}

void glPrintB (const char *fmt, ...)// Заказная функция «Печати» GL
{
 float length=0; // Переменная для нахождения физической длины текста
 char text [256];// Здесь наша строка
 va_list ap;     // Указатель на переменный список аргументов
 if (fmt==NULL)  // Если нет текста
  return;        // Ничего не делать

 va_start (ap, fmt);         // Анализ строки на переменные
 vsprintf (text, fmt, ap);   // И конвертация символов в реальные коды
 va_end (ap);                // Результат сохраняется в text

 for (int i=0; i<strlen (text); i++)// %
 {
  if (text [i]==17)
   text [i]=37;
 }

 glPushAttrib (GL_LIST_BIT);    // Сохраняет в стеке значения битов списка отображения
 glListBase (base);             // Устанавливает базовый символ в 0

 // Создает списки отображения текста
 glCallLists (strlen (text), GL_UNSIGNED_BYTE, text);
 glPopAttrib ();// Восстанавливает значение Display List Bits
}


GLuint bgList, brdList, infList, bgListB;

float brdX=1.0f, brdY=1.0f, brdZ=-2.4325f;
float brdS=2.0f;
float brdL=-brdS*5.5f/9.0f, brdR=brdL+brdS;
float brdT=brdS/2.0f, brdB=-brdS/2.0f;

void BuildLists ()// создаем список отображения
{
 int i;

 bgList=glGenLists (12);// создаем списки

 float bgQ=sqrt (pow (cx, 2)+pow (cy, 2))/(float)cx;
 float bgX=1.825f*((float(cx)/float(cy))/(1600.0f/900.0f))*bgQ, bgY=bgX, bgZ=0.0f;

 glNewList (bgList, GL_COMPILE);// Новый откомпилированный список отображения
 glBindTexture (GL_TEXTURE_2D, texture [1]);
 glBegin (GL_QUADS);
 glTexCoord2f (0.0f, 0.0f); glVertex3f (-bgX, -bgY, bgZ);// Низ лево
 glTexCoord2f (1.0f, 0.0f); glVertex3f ( bgX, -bgY, bgZ);// Низ право
 glTexCoord2f (1.0f, 1.0f); glVertex3f ( bgX,  bgY, bgZ);// Верх право
 glTexCoord2f (0.0f, 1.0f); glVertex3f (-bgX,  bgY, bgZ);// Верх лево
 glEnd ();
 glEndList ();// Закончили создание списка

 brdList=bgList+1;
 glNewList (brdList, GL_COMPILE);
 glBindTexture (GL_TEXTURE_2D, texture [0]);
 glBegin (GL_QUADS);
 glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL, brdB, brdZ);// Низ лево
 glTexCoord2f (1.0f, 0.0f); glVertex3f (brdR, brdB, brdZ);// Низ право
 glTexCoord2f (1.0f, 1.0f); glVertex3f (brdR, brdT, brdZ);// Верх право
 glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL, brdT, brdZ);// Верх лево
 glEnd ();
 glEndList ();// Закончили создание списка

 infList=brdList+1;
 glNewList (infList, GL_COMPILE);
 glBindTexture (GL_TEXTURE_2D, texture [13]);
 glBegin (GL_QUADS);
 glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL, brdB, brdZ);// Низ лево
 glTexCoord2f (1.0f, 0.0f); glVertex3f (brdR, brdB, brdZ);// Низ право
 glTexCoord2f (1.0f, 1.0f); glVertex3f (brdR, brdT, brdZ);// Верх право +0.00135f
 glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL, brdT, brdZ);// Верх лево +0.001f
 glEnd ();
 glEndList ();// Закончили создание списка
}

COLORREF ig1=RGB (170, 170, 170), ig2=RGB (185, 185, 185), iw=RGB (240, 240, 240);
bool isGray (COLORREF px)
{
 if (px>ig1 && px<ig2)
  return true;
 return false;
}

bool isWhite (COLORREF px)
{
 if (px>iw)
  return true;
 return false;
}

void paint ()
{
 if (pC<10 && !(pLoad>0.0f))
  pC++;

 // OpenGL animation code goes here
 glPushMatrix ();
 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glDisable (GL_DEPTH_TEST);// Выключаем тест глубины
 glEnable (GL_MULTISAMPLE_ARB);


 // Фон
 glLoadIdentity ();  // Сброс просмотра
 glTranslatef (0.0f, 0.0f, -2.4f);
 glRotatef (-bgAngle, 0.0f, 0.0f, 1.0f);

 bgAngle+=0.05f*fpsTweak ();
 if (bgAngle>180.0f)
  bgAngle-=360.0f;

 glColor3f (1.0f, 1.0f, 1.0f);
 glCallList (bgList);


 glDisable (GL_MULTISAMPLE_ARB);


 // Доска
 glLoadIdentity ();  // Сброс просмотра


 // Intro
 if (pLoad>0.0f)
 {
  pLoad-=1.0f*fpsTweak ();
  glTranslatef (0.0f, 0.0f, loadFar);
  glRotatef (-loadAngle, 0.0f, 0.0f, 1.0f);
  loadFar+=loadFarStep*fpsTweak ();
  loadAngle+=loadAngleStep*fpsTweak ();
 }


 glColor3f (1.0f, 1.0f, 1.0f);
 glCallList (brdList);


 // Тёмные клетки
 glColor3f (1.0f, 1.0f, 1.0f);
 glBindTexture (GL_TEXTURE_2D, texture [2]);

 float brdCell=brdS/9.0f;
 float brdL2=brdL+brdS/9.0f, brdT2=brdT-brdS/9.0f;
 int xi, yi, c=0;
 for (yi=0; yi<8; yi++)
 {
  c++;

  for (xi=0; xi<8; xi++)
  {
   c++;
   if (c%2)
   {
    glBegin (GL_QUADS);
    glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xi*brdCell, brdT2-(yi+1)*brdCell, brdZ);    // Низ лево
    glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT2-(yi+1)*brdCell, brdZ);// Низ право
    glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT2-yi*brdCell, brdZ);    // Верх право
    glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xi*brdCell, brdT2-yi*brdCell, brdZ);        // Верх лево
    glEnd ();
   }
  }
 }


 // Угол доски
 glColor3f (1.0f, 1.0f, 1.0f);
 glBindTexture (GL_TEXTURE_2D, texture [5]);
 glBegin (GL_QUADS);
 glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL, brdT-brdCell, brdZ);        // Низ лево
 glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL+brdCell, brdT-brdCell, brdZ);// Низ право
 glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL+brdCell, brdT, brdZ);        // Верх право
 glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL, brdT, brdZ);                // Верх лево
 glEnd ();


 // Верхний край доски
 glColor3f (1.0f, 1.0f, 1.0f);
 glBindTexture (GL_TEXTURE_2D, texture [4]);
 for (xi=0; xi<8; xi++)
 {
  glBegin (GL_QUADS);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xi*brdCell, brdT-brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT-brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT, brdZ);        // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xi*brdCell, brdT, brdZ);            // Верх лево
  glEnd ();
 }


 // Левый
 glColor3f (1.0f, 1.0f, 1.0f);
 glBindTexture (GL_TEXTURE_2D, texture [3]);
 for (yi=0; yi<8; yi++)
 {
  glBegin (GL_QUADS);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL, brdT2-(yi+1)*brdCell, brdZ);        // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL+brdCell, brdT2-(yi+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL+brdCell, brdT2-yi*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL, brdT2-yi*brdCell, brdZ);            // Верх лево
  glEnd ();
 }


 // Уточнение координат клеток
 if (pC==2)
 {
  int xs, ys=cy/2, xi2, yi2, c=0, i;
  bool chk;

  xs=mXar0 [0]-(mXar0 [1]-mXar0 [0])/2;

  for (xi=xs; xi<cx; xi++)
  {
   pixel=GetPixel (hDC, xi, ys);

   if ((isGray (pixel) && (c+1)%2) || (isWhite (pixel) && !((c+1)%2)))
   {
    chk=true;
    for (xi2=0; xi2<5; xi2++)
    {
     pixel=GetPixel (hDC, xi+xi2+1, ys);
     if ((!isGray (pixel) && (c+1)%2) || (!isWhite (pixel) && !((c+1)%2)))
      chk=false;
    }
    if (chk)
    {
     mXar1 [c]=xi;
     c++;
     if (c==8)
      break;      
    }
   }
  }

  if (c==8)
  {
   ys=cy/2+(mYar0 [1]-mYar0 [0]);
   for (i=xi+10; i<cx; i++)
   {
    pixel=GetPixel (hDC, i, ys);
    if (!isGray (pixel))
    {
     mXar1 [c]=i;
     break;
    }
   }
  }

  int mx=0, mxd;
  for (i=0; i<9; i++)
  {
   mxd=abs (mXar1 [i]-mXar0 [i]);
   if (mxd>mx)
    mx=mxd;
  }
  if (mx<25)
  {
   for (i=0; i<9; i++)
    mXar [i]=mXar1 [i];
  }
  else
  {
   for (i=0; i<9; i++)
    mXar [i]=mXar0 [i];
  }

  ys=mYar0 [0]-(mYar0 [1]-mYar0 [0])/2; xs=mXar [0]+(mXar [1]-mXar [0])/2; c=0;

  for (yi=ys; yi<cy; yi++)
  {
   pixel=GetPixel (hDC, xs, yi);

   if ((isGray (pixel) && !((c+1)%2)) || (isWhite (pixel) && (c+1)%2))
   {
    chk=true;
    for (yi2=0; yi2<5; yi2++)
    {
     pixel=GetPixel (hDC, xs, yi+yi2+1);
     if ((!isGray (pixel) && !((c+1)%2)) || (!isWhite (pixel) && (c+1)%2))
      chk=false;
    }
    if (chk)
    {
     mYar1 [c]=yi;
     c++;
     if (c==8)
      break;  
    }
   }
  }

  if (c==8)
  {
   mYar1 [c]=cy;

   for (i=yi+10; i<cy+10; i++)
   {
    pixel=GetPixel (hDC, xs, i);
    if (!isGray (pixel))
    {
     mYar1 [c]=i;
     break;
    }
   }
  }

  for (i=0; i<9; i++)
  {
   mxd=abs (mYar1 [i]-mYar0 [i]);
   if (mxd>mx)
    mx=mxd;
  }
  if (mx<25)
  {
   for (i=0; i<9; i++)
    mYar [i]=mYar1 [i];
  }
  else
  {
   for (i=0; i<9; i++)
    mYar [i]=mYar0 [i];
  }
  moreFPS=false;

  ShowCursor (true);
  mouseMove ();
  SetTimer (hWnd, TIMER_MEL, 1000, NULL);
  playSound ("board");
 }


 if (pC>1)
 {
  // Выделение клетки
  if (rvOn || turn!=1)
   glColor3f (colorCellOff [0], colorCellOff [1], colorCellOff [2]);
  else if (posHL)
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  else
   glColor3f (colorCellHL0 [0], colorCellHL0 [1], colorCellHL0 [2]);

  glBindTexture (GL_TEXTURE_2D, texture [0]);
  glBegin (GL_QUADS);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+posX*brdCell, brdT2-(posY+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(posX+1)*brdCell, brdT2-(posY+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(posX+1)*brdCell, brdT2-posY*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+posX*brdCell, brdT2-posY*brdCell, brdZ);        // Верх лево
  glEnd ();


  // Выделение Y-координаты
  glColor3f (1.0f, 1.0f, 1.0f);
  glBindTexture (GL_TEXTURE_2D, texture [6]);
  glBegin (GL_QUADS);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL, brdT2-(posY+1)*brdCell, brdZ);        // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL+brdCell, brdT2-(posY+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL+brdCell, brdT2-posY*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL, brdT2-posY*brdCell, brdZ);            // Верх лево
  glEnd ();


  // X
  glColor3f (1.0f, 1.0f, 1.0f);
  glBindTexture (GL_TEXTURE_2D, texture [7]);
  glBegin (GL_QUADS);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+posX*brdCell, brdT-brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(posX+1)*brdCell, brdT-brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(posX+1)*brdCell, brdT, brdZ);        // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+posX*brdCell, brdT, brdZ);            // Верх лево
  glEnd ();


  glEnable (GL_MULTISAMPLE_ARB);// Enable Our Multisampling


  // Наименование координат
  char literaL [10]={'8', '7', '6', '5', '4', '3', '2', '1'};
  char literaT [10]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
  glBindTexture (GL_TEXTURE_2D, texture [0]);

  for (xi=0; xi<8; xi++)
  {
   if (xi==posX)
    glColor3f (colorCoordHL [0], colorCoordHL [1], colorCoordHL [2]);
   else
    glColor3f (colorCoordX [0], colorCoordX [1], colorCoordX [2]);

   glLoadIdentity ();// Сброс просмотра

   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xi, brdT-brdCell/2.0f-0.0255f, brdZ);
   glScalef (0.07f, 0.07f, 1.0f);
   glPrintB ("%c", literaT [xi]);// Печать текста GL на экран
  }

  for (yi=0; yi<8; yi++)
  {
   if (yi==posY)
    glColor3f (colorCoordHL [0], colorCoordHL [1], colorCoordHL [2]);
   else
    glColor3f (colorCoordY [0], colorCoordY [1], colorCoordY [2]);
   glLoadIdentity ();// Сброс просмотра
   glTranslatef (brdL+brdCell/2.0f-0.023f, brdT2-brdCell/2.0f-0.0255f-brdCell*yi, brdZ);
   glScalef (0.07f, 0.07f, 1.0f);
   glPrintB ("%c", literaL [yi]);// Печать текста GL на экран
  }


  // Фишки
  if (rvOn)
  {
   rvC+=fpsTweak ();
   rvAngle-=360.0f/rvSteps*fpsTweak ();
   rvWidth+=rvWstep*fpsTweak ();
   if (rvWidth>=rvWmx)
   {
    rvWidth=rvWmx;
    rvWstep*=-1;
   }
   if (rvC>=rvSteps)
   {
    for (yi=0; yi<8; yi++)
    {
     for (xi=0; xi<8; xi++)
     {
      if (init_d [getPos (xi, yi)]==3)
       init_d [getPos (xi, yi)]=1;
      else if (init_d [getPos (xi, yi)]==4)
       init_d [getPos (xi, yi)]=2;
     }
    }
    rvOn=false;
    if (rvSide==1)
     turn=2;
    else
    {
     if (isMove ())
     {
      turn=1;
      cellInfo ();
      SetCursor (curArrow);
     }
     else
     {
      moveOff++;
      if (moveOff==2 || cPlayer+cCPU==64)
       turnOver ();
      else
      {
       turn=2;
       playSound ("break");
      }
     }
    }
   }
  }
  if (turn==4 && toCur)// ?
  {
   toCur=false;
   SetCursor (curNew);
  }
  if (turn==1 && arCur)// ?
  {
   arCur=false;
   SetCursor (curArrow);
  }

  glLoadIdentity ();// Сброс просмотра

  glEnable (GL_BLEND);
  glBindTexture (GL_TEXTURE_2D, texture [8]);
  glBegin (GL_QUADS);

  int xi, yi, c=0;
  for (yi=0; yi<8; yi++)
  {
   for (xi=0; xi<8; xi++)
   {
    if (init_d [c]!=0 && !(rvOn && xi==rvX && yi==rvY))
    {
     if (init_d [c]==1)
      glColor3f (colorPlayer [0], colorPlayer [1], colorPlayer [2]);
     else if (init_d [c]==2)
      glColor3f (colorCPU [0], colorCPU [1], colorCPU [2]);
     else if (init_d [c]==3)
      glColor3f (colorCPU [0]+(colorPlayer [0]-colorCPU [0])/rvSteps*rvC,
                 colorCPU [1]+(colorPlayer [1]-colorCPU [1])/rvSteps*rvC,
                 colorCPU [2]+(colorPlayer [2]-colorCPU [2])/rvSteps*rvC);
     else if (init_d [c]==4)
      glColor3f (colorPlayer [0]+(colorCPU [0]-colorPlayer [0])/rvSteps*rvC,
                 colorPlayer [1]+(colorCPU [1]-colorPlayer [1])/rvSteps*rvC,
                 colorPlayer [2]+(colorCPU [2]-colorPlayer [2])/rvSteps*rvC);

     glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xi*brdCell, brdT2-(yi+1)*brdCell, brdZ);    // Низ лево
     glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT2-(yi+1)*brdCell, brdZ);// Низ право
     glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xi+1)*brdCell, brdT2-yi*brdCell, brdZ);    // Верх право
     glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xi*brdCell, brdT2-yi*brdCell, brdZ);        // Верх лево
    }
    c++;
   }
  }


  // Статистика
  float xr=8.1f, yr=0.0f;
  glColor3f (colorPlayer [0], colorPlayer [1], colorPlayer [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево

  yr=1.0f;
  glColor3f (colorCPU [0], colorCPU [1], colorCPU [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево

  glEnd ();


  // Кнопки
  xr=8.1f, yr=3.0f;
  glBindTexture (GL_TEXTURE_2D, texture [10]);
  glBegin (GL_QUADS);
  if (button!=1)
   glColor3f (colorRestB [0], colorRestB [1], colorRestB [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
  glEnd ();

  xr=8.1f, yr=4.0f;
  glBindTexture (GL_TEXTURE_2D, texture [11]);
  glBegin (GL_QUADS);
  if (button!=2)
   glColor3f (colorRestB [0], colorRestB [1], colorRestB [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
  glEnd ();

  xr=8.1f, yr=5.0f;
  glBindTexture (GL_TEXTURE_2D, texture [14]);
  glBegin (GL_QUADS);
  if (button!=3)
   glColor3f (colorRestB [0], colorRestB [1], colorRestB [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
  glEnd ();

  xr=8.1f, yr=6.0f;
  glBindTexture (GL_TEXTURE_2D, texture [12]);
  glBegin (GL_QUADS);
  if (button!=4)
   glColor3f (colorRestB [0], colorRestB [1], colorRestB [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
  glEnd ();

  xr=8.1f, yr=7.0f;
  glBindTexture (GL_TEXTURE_2D, texture [9]);
  glBegin (GL_QUADS);
  if (button!=5)
   glColor3f (colorExitB [0], colorExitB [1], colorExitB [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
  glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
  glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+1)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
  glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
  glEnd ();

  glDisable (GL_BLEND);


  // Количество фишек
  glBindTexture (GL_TEXTURE_2D, texture [0]);
  xr=8.8f; yr=0.0f;
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
  glPrintB ("%d", cPlayer);// Печать текста GL на экран
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorPlayerStat [0], colorPlayerStat [1], colorPlayerStat [2]);
  glPrintB ("%d", cPlayer);// Печать текста GL на экран
  
  yr=1.0f;
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
  glPrintB ("%d", cCPU);// Печать текста GL на экран
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorCPUStat [0], colorCPUStat [1], colorCPUStat [2]);
  glPrintB ("%d", cCPU);// Печать текста GL на экран

  // Громкость
  yr=3.0f;
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
  glPrintB ("%d", sndVol);// Печать текста GL на экран
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  if (button!=1)
   glColor3f (colorVol [0], colorVol [1], colorVol [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glPrintB ("%d", sndVol);// Печать текста GL на экран

  yr=4.0f;
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
  glPrintB ("%d", melVol);// Печать текста GL на экран
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  if (button!=2)
   glColor3f (colorVol [0], colorVol [1], colorVol [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glPrintB ("%d", melVol);// Печать текста GL на экран

  // ИИ
  yr=5.0f;
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
  glPrintB ("%d", AI);// Печать текста GL на экран
  glLoadIdentity ();// Сброс просмотра
  glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
  glScalef (0.12f, 0.12f, 1.0f);
  if (button!=3)
   glColor3f (colorVol [0], colorVol [1], colorVol [2]);
  else
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
  glPrintB ("%d", AI);// Печать текста GL на экран

  // Таймер выхода
  if (qC!=0)
  {
   yr=7.0f;
   glLoadIdentity ();// Сброс просмотра
   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
   glScalef (0.12f, 0.12f, 1.0f);
   glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
   glPrintB ("%d", qCmx-qC);// Печать текста GL на экран
   glLoadIdentity ();// Сброс просмотра
   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
   glScalef (0.12f, 0.12f, 1.0f);
   if (button!=5)
    glColor3f (colorExitT [0], colorExitT [1], colorExitT [2]);
   else
    glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
   glPrintB ("%d", qCmx-qC);// Печать текста GL на экран
  }


  // Реверсная фишка
  if (rvOn)
  {
   xr=rvX, yr=rvY;
   glLoadIdentity ();// Сброс просмотра
   glEnable (GL_BLEND);
   glTranslatef (brdL2+(xr+1)*brdCell-brdCell/2.0f, brdT2-(yr+1)*brdCell+brdCell/2.0f, brdZ);
   glRotatef (rvAngle, 0.0f, 0.0f, 1.0f);
   glBindTexture (GL_TEXTURE_2D, texture [8]);
   glBegin (GL_QUADS);
   if (rvSide==1)
    glColor3f (colorPlayer [0], colorPlayer [1], colorPlayer [2]);
   else
    glColor3f (colorCPU [0], colorCPU [1], colorCPU [2]);
   glTexCoord2f (0.0f, 0.0f); glVertex3f (-brdCell/(2.0f+rvWidth), -brdCell/2.0f, 0.0f);// Низ лево
   glTexCoord2f (1.0f, 0.0f); glVertex3f (brdCell/(2.0f+rvWidth), -brdCell/2.0f, 0.0f); // Низ право
   glTexCoord2f (1.0f, 1.0f); glVertex3f (brdCell/(2.0f+rvWidth), brdCell/2.0f, 0.0f);  // Верх право
   glTexCoord2f (0.0f, 1.0f); glVertex3f (-brdCell/(2.0f+rvWidth), brdCell/2.0f, 0.0f); // Верх лево
   glEnd ();
   glDisable (GL_BLEND);
  }

  if (turn==4)
  {
   glLoadIdentity ();// Сброс просмотра

   glEnable (GL_BLEND);
   glColor4f(1.0, 1.0, 1.0, 0.0f+(90.0f-resultAngle)/255.0f);
   glBindTexture (GL_TEXTURE_2D, texture [0]);
   glBegin (GL_QUADS);
   glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2, brdB, brdZ);// Низ лево
   glTexCoord2f (1.0f, 0.0f); glVertex3f (brdR, brdB, brdZ);// Низ право
   glTexCoord2f (1.0f, 1.0f); glVertex3f (brdR, brdT2, brdZ);// Верх право +0.00135f
   glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2, brdT2, brdZ);// Верх лево +0.001f
   glEnd ();
   glDisable (GL_BLEND);

   if (cPlayer>cCPU)
    sprintf (txt, "Выигрыш");
   else if (cPlayer<cCPU)
    sprintf (txt, "Проигрыш");
   else
    sprintf (txt, "Ничья");

   if (resultAngle>0.0f)
    resultAngle-=fpsTweak ();
   else if (!resultOff)
   {
    resultAngle=0.0f;
    resultOff=true;
    if (cPlayer>cCPU)
     playSound ("speech_win");
    else if (cPlayer<cCPU)
     playSound ("speech_lose");
    else
     playSound ("speech_draw");
   }

   glBindTexture (GL_TEXTURE_2D, texture [0]);

   glLoadIdentity ();// Сброс просмотра
   glTranslatef (0.01f, -0.01f, 0.0f);
   glTranslatef (-0.124f, -0.082, brdZ);
   glRotatef (-resultAngle, 1.0f, 0.0f, 0.0f);
   glTranslatef (-0.0f, -0.082f, 0.0f);
   glScalef (0.32f, 0.32f, 0.0f);
   glColor3f (0.1f, 0.1f, 0.1f);
   glPrint ("%s", txt);// Печать текста GL на экран

   glLoadIdentity ();// Сброс просмотра
   glTranslatef (-0.124f, -0.082, brdZ);
   glRotatef (-resultAngle, 1.0f, 0.0f, 0.0f);
   glTranslatef (-0.0f, -0.082f, 0.0f);
   glScalef (0.32f, 0.32f, 0.0f);
   glColor3f (colorH [0], colorH [1], colorH [2]);
   glPrint ("%s", txt);// Печать текста GL на экран
  }


  if (button)
  {
   xr=5.0f;

   if (button==1)
   {
    yr=3.0f;
    sprintf (txt, "     звук");
   }
   else if (button==2)
   {
    yr=4.0f;
    sprintf (txt, "  мелодия");
   }
   else if (button==3)
   {
    yr=5.0f;
    sprintf (txt, "сложность");
   }
   else if (button==4)
   {
    yr=6.0f;
    sprintf (txt, "  справка");
   }
   else if (button==5)
   {
    yr=7.0f;
    sprintf (txt, "    выход");
   }

   glLoadIdentity ();// Сброс просмотра
   glDisable (GL_MULTISAMPLE_ARB);
   glEnable (GL_BLEND);
   glColor4f(1.0, 1.0, 1.0, 0.85f);
   glBindTexture (GL_TEXTURE_2D, texture [15]);
   glBegin (GL_QUADS);
   glTexCoord2f (0.0f, 0.0f); glVertex3f (brdL2+xr*brdCell, brdT2-(yr+1)*brdCell, brdZ);    // Низ лево
   glTexCoord2f (1.0f, 0.0f); glVertex3f (brdL2+(xr+3)*brdCell, brdT2-(yr+1)*brdCell, brdZ);// Низ право
   glTexCoord2f (1.0f, 1.0f); glVertex3f (brdL2+(xr+3)*brdCell, brdT2-yr*brdCell, brdZ);    // Верх право
   glTexCoord2f (0.0f, 1.0f); glVertex3f (brdL2+xr*brdCell, brdT2-yr*brdCell, brdZ);        // Верх лево
   glEnd ();
   glDisable (GL_BLEND);
   glEnable (GL_MULTISAMPLE_ARB);// Enable Our Multisampling

   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*yr-0.0025f, brdZ);
   glScalef (0.12f, 0.12f, 1.0f);
   glColor3f (colorShadow [0], colorShadow [1], colorShadow [2]);
   glPrintB ("%s", txt);// Печать текста GL на экран
   glLoadIdentity ();// Сброс просмотра
   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr, brdT2-brdCell/2.0f-0.0255f-brdCell*yr, brdZ);
   glScalef (0.12f, 0.12f, 1.0f);
   glColor3f (colorCellHL1 [0], colorCellHL1 [1], colorCellHL1 [2]);
   glPrintB ("%s", txt);// Печать текста GL на экран
  }


  if (infOn)
  {
   glLoadIdentity ();// Сброс просмотра
   glEnable (GL_BLEND);
   glColor4f(1.0, 1.0, 1.0, 0.9f);
   glCallList (infList);
   glDisable (GL_BLEND);

   glBindTexture (GL_TEXTURE_2D, texture [0]);
   glColor3f (colorH [0], colorH [1], colorH [2]);
   glTranslatef (-0.224f, 0.55f, brdZ);
   glScalef (0.32f, 0.32f, 0.0f);
   glPrint ("Repaint");// Печать текста GL на экран

   char infTxt [10] [100]={" Задача игры - составлять горизонтальные,",
                          "вертикальные и диагональные линии.",
                          "Для этого нужно замыкать своими фишками",
                          "находящиеся между ними фишки компьютера.",
                          "Выигрывает тот, кто займёт большую часть",
                          "доски."
                       };
   xr=-0.25f; yr=1.75f;

   glLoadIdentity ();// Сброс просмотра
   glColor3f (colorTxt [0], colorTxt [1], colorTxt [2]);

   for (yi=0; yi<6; yi++)
   {
    glLoadIdentity ();// Сброс просмотра
    glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*(yr+yi*0.5f)-0.0025f, brdZ);
    glScalef (0.07f, 0.07f, 1.0f);
    glPrintB ("%s", infTxt [yi]);// Печать текста GL на экран
   }

   xr=-0.25f; yr=1.75f;
   glLoadIdentity ();// Сброс просмотра
   glColor3f (colorTxtB [0], colorTxtB [1], colorTxtB [2]);
   glTranslatef (brdL2+brdCell/2.0f-0.023f+brdCell*xr+0.0025f, brdT2-brdCell/2.0f-0.0255f-brdCell*(yr+9*0.5f)-0.0025f, brdZ);
   glScalef (0.07f, 0.07f, 1.0f);
   glPrintB ("                         Маркичев Д. 2018");// Печать текста GL на экран
  }
 }

 fpsC ();
// statusBar ();

 glEnable (GL_DEPTH_TEST);// Выключаем тест глубины
 glPopMatrix ();
 SwapBuffers (hDC);
}

void mouseMove ()
{
 int xi, yi;

 if (blur_on)
  return;

 GetCursorPos (&mypoint);

 if (infOn && mypoint.x>=mXar [0]-(mXar [1]-mXar [0]) && mypoint.x<mXar [8] && mypoint.y>=mYar [0]-(mYar [1]-mYar [0]) && mypoint.y<mYar [8])
 {
  SetCursor (curOff);
  return;
 }

 int field=0, fldX=posX, fldY=posY;
 for (xi=0; xi<9; xi++)
 {
  if (mypoint.x>=mXar [xi] && mypoint.x<mXar [xi+1])
  {
   posX=xi;
   field++;

   break;
  }
 }

 for (yi=0; yi<9; yi++)
 {
  if (mypoint.y>=mYar [yi] && mypoint.y<mYar [yi+1])
  {
   posY=yi;
   field++;
   break;
  }
 }

 if (field<2)
 {
  posX=fldX;
  posY=fldY;
 }

 if (posX!=posXl || posY!=posYl)
  cellInfo ();

 int bL=button;
 button=0;
 float ri, qi=float(mXar [8]-mXar [7])/25.0f;

 if ((mypoint.x>(mXar [8]+(mXar [8]-mXar [7])/10) && mypoint.x<(mXar [8]+(mXar [8]-mXar [7])*11/10)))
 {
  if (mypoint.y>=mYar [7] && mypoint.y<mYar [8])
  {
   xi=abs ((float)mypoint.x-((float)mXar [8]+float(mXar [8]-mXar [7])*6.0f/10.0f));
    yi=abs ((float)mypoint.y-((float)mYar [7]+float(mYar [8]-mYar [7])*39.0f/40.0f/2.0f));
   ri=sqrt (pow (xi, 2)+pow (yi, 2));
   if (ri<float(mXar [8]-mXar [7])/2.0f-qi)
    button=5;
  }
  if (mypoint.y>=mYar [6] && mypoint.y<mYar [7])
  {
   xi=abs ((float)mypoint.x-((float)mXar [8]+float(mXar [8]-mXar [7])*6.0f/10.0f));
    yi=abs ((float)mypoint.y-((float)mYar [6]+float(mYar [8]-mYar [7])*39.0f/40.0f/2.0f));
   ri=sqrt (pow (xi, 2)+pow (yi, 2));
   if (ri<float(mXar [8]-mXar [7])/2.0f-qi)
    button=4;
  }
  if (mypoint.y>=mYar [5] && mypoint.y<mYar [6])
  {
   xi=abs ((float)mypoint.x-((float)mXar [8]+float(mXar [8]-mXar [7])*6.0f/10.0f));
   yi=abs ((float)mypoint.y-((float)mYar [5]+float(mYar [8]-mYar [7])*39.0f/40.0f/2.0f));
   ri=sqrt (pow (xi, 2)+pow (yi, 2));
   if (ri<float(mXar [8]-mXar [7])/2.0f-qi)
    button=3;
  }
  if (mypoint.y>=mYar [4] && mypoint.y<mYar [5])
  {
   xi=abs ((float)mypoint.x-((float)mXar [8]+float(mXar [8]-mXar [7])*6.0f/10.0f));
   yi=abs ((float)mypoint.y-((float)mYar [4]+float(mYar [8]-mYar [7])*39.0f/40.0f/2.0f));
   ri=sqrt (pow (xi, 2)+pow (yi, 2));
   if (ri<float(mXar [8]-mXar [7])/2.0f-qi)
    button=2;
  }
  if (mypoint.y>=mYar [3] && mypoint.y<mYar [4])
  {
   xi=abs ((float)mypoint.x-((float)mXar [8]+float(mXar [8]-mXar [7])*6.0f/10.0f));
   yi=abs ((float)mypoint.y-((float)mYar [3]+float(mYar [8]-mYar [7])*39.0f/40.0f/2.0f));
   ri=sqrt (pow (xi, 2)+pow (yi, 2));
   if (ri<float(mXar [8]-mXar [7])/2.0f-qi)
    button=1;
  }
 }

 if (bL!=button && button!=0)
  playSound ("select");

 if (turn==4)
 {
  if (mypoint.x>=mXar [0] && mypoint.x<mXar [8] && mypoint.y>=mYar [0] && mypoint.y<mYar [8])
   SetCursor (curNew);
 }
 else if ((rvOn || (turn!=1 && turn!=4)) && !button)
  SetCursor (curWait);
}

void mouseClick ()
{
 GetCursorPos (&mypoint);

 if (infOn && mypoint.x>=mXar [0]-(mXar [1]-mXar [0]) && mypoint.x<mXar [8] && mypoint.y>=mYar [0]-(mYar [1]-mYar [0]) && mypoint.y<mYar [8])
 {
  infOn=false;
  playSound ("shake");
  mouseMove ();
  return;
 }

 if (!button)
 {
  if (turn==4)
  {
   if (mypoint.x>=mXar [0] && mypoint.x<mXar [8] && mypoint.y>=mYar [0] && mypoint.y<mYar [8])
   {
    memcpy (init_d, init_p, 64);
    playSound ("board");
    SetCursor (curArrow);
    turn=1;
    cPlayer=2;
    cCPU=2;
   }
  }
  else
  {
   if (rvOn || (turn!=1 && turn!=4))
   {
    SetCursor (curWait);
    return;
   }

   playerMove ();
  }
 }
 else if (button==1)
 {
  sndVol++;
  if (sndVol>4)
   sndVol=0;

  soundVol=sndVol*250;
  if (sndVol!=0)
  {
   if (sndVol==1)
    soundOn=true;
   playSound ("turn_on");
  }
  else
  {
   soundOn=false;
   playSound ("turn_off", 100, 25);
  }
 }
 else if (button==2)
 {
  melVol++;
  if (melVol>4)
   melVol=0;

  if (melVol==0)
  {
   meloTurnOff=true;
   playSound ("turn_off");
  }
  else if (melVol==1)
   meloTurnOn=true;

  if (melVol>0)
   playSound ("turn_on");

  meloVol=0;
  SetTimer (hWnd, TIMER_MELON, 1000, NULL);
 }
 else if (button==3)
 {
  AI++;
  if (AI>2)
   AI=0;
  if (AI==0)
   playSound ("turn_off");
  else
   playSound ("turn_on");
 }
 else if (button==4)
 {
  if (!infOn)
  {
   infOn=true;
   playSound ("shake");
  }
  else
  {
   infOn=false;
   playSound ("shake");
  }
 }
 else if (button==5)
 {
  if (qC==0)
  {
   qC=1;
   playSound ("turn_on");
   SetTimer (hWnd, TIMER_QUIT, 1000, NULL);
  }
  else
  {
   KillTimer (hWnd, TIMER_QUIT);
   qC=0;
   playSound ("turn_off");
  }
 }
}

int getPos (int x, int y)
{
 int p;

 if (x>-1 && x<8 && y>-1 && y<8)
  p=y*8+x;
 else
  p=0;

 return p;
}

void playerMove ()
{
 if (posHL)
 {
  moveOff=0;
  memcpy (rv_d, init_d, 64);
  reverse (posX, posY, 1, 1);
  memcpy (init_d, rv_d, 64);
  init_d [getPos (posX, posY)]=1;
  rvC=0.0f;
  rvX=posX;
  rvY=posY;
  rvSide=1;
  rvAngle=0.0f;
  rvWidth=0.0f;
  rvWstep=rvWmx*2.0f/rvSteps;
  rvOn=true;
  SetCursor (curWait);
  cCPU-=cMove;
  cPlayer+=cMove+1;
  char t [16];
  sprintf (t, "move%d", (rand ()%5+1));
  playSound (t);
  cellInfo ();
 }
 else
  playSound ("break");
}

int reverse (int x, int y, int side, int mode)
{
 int xi, yi, c, c1, c2, s1, s2, r=0;

 if (rv_d [getPos (x, y)]!=0)
  return 0;

 if (side==1)
 {
  s1=1;
  s2=2;
 }
 else
 {
  s1=2;
  s2=1;
 }

 int ar [8] [6]={x+1, 8, 1, y, -1, 0,
                 x-1, -1, -1, y, -1, 0,
                 x, -1, 0, y+1, 8, 1,
                 x, -1, 0, y-1, -1, -1,
                 x+1, 8, 1, y+1, 8, 1,
                 x+1, 8, 1, y-1, -1, -1,
                 x-1, -1, -1, y+1, 8, 1,
                 x-1, -1, -1, y-1, -1, -1
                };

 c1=0;
 while (c1<8)
 {
  xi=ar [c1] [0];
  yi=ar [c1] [3];

  if (!(xi<0 || xi>7 || yi<0 || yi>7))
  {
   c=0; c2=0;

   while ((xi!=ar [c1] [1] || ar [c1] [2]==0) && (yi!=ar [c1] [4] || ar [c1] [5]==0))
   {
    if (rv_d [getPos (xi, yi)]==0)
     break;
    else if (rv_d [getPos (xi, yi)]==s1)
    {
     if (c)
     {
      c++;
      r+=c2;
     }
     break;
    }
    else if (rv_d [getPos (xi, yi)]==s2)
    {
     c=1;
     c2++;
    }

    xi+=ar [c1] [2];
    yi+=ar [c1] [5];
   }

   if (mode!=0 && c==2)
   {
    xi=ar [c1] [0];
    yi=ar [c1] [3];

    while ((xi!=ar [c1] [1] || ar [c1] [2]==0) && (yi!=ar [c1] [4] || ar [c1] [5]==0))
    {
     if (rv_d [getPos (xi, yi)]==s2)
      rv_d [getPos (xi, yi)]=(mode==1 ? s1+2 : s1);
     else if (rv_d [getPos (xi, yi)]==s1)
      break;

     xi+=ar [c1] [2];
     yi+=ar [c1] [5];
    }
   }
  }

  c1++;
 }

 return r;
}

void cellInfo ()
{
 int r;

 posXl=posX;
 posYl=posY;

 memcpy (rv_d, init_d, 64);
 cMove=reverse (posX, posY, 1);
 if (cMove)
  posHL=1;
 else
  posHL=0;
}


float fpsTweak ()
{
 if (!clockTweak)
  return 1.0f;
 else
  return clockD/15.0f;// 1 frame ms tweak
}

void fpsC ()
{
 // FPS
 paintC++;
 if (clock ()-timeS>=1000)
 {
  fps=paintC;
  paintC=0;
  timeS=clock ();
  if (fpsOn<10)
   fpsOn++;
 }

 clockTweak=false;
 if (clockL!=0)
  clockTweak=true;

 clockD=(float)clock ()-(float)clockL;
 clockL=clock ();
}

void statusBar ()
{
 if (fps>-1)
 {
  if (strlen (mb)!=0)
  {
   glDisable (GL_DEPTH_TEST);// Выключаем тест глубины
   glBindTexture (GL_TEXTURE_2D, texture [0]);
   glLoadIdentity ();// Сброс просмотра
   glTranslatef (0.0f, 1.75f, -5.0f);
   glScalef (0.17f, 0.17f, 1.0f);
   glColor3f (1.0f, 1.0f, 1.0f);
//   glPrint ("test");// Печать текста GL на экран
   glPrint ("%s", mb);// Печать текста GL на экран
   glEnable (GL_DEPTH_TEST);// Включаем тест глубины
   return;
  }

  glDisable (GL_DEPTH_TEST);// Выключаем тест глубины

  glBindTexture (GL_TEXTURE_2D, texture [0]);

  glLoadIdentity ();// Сброс просмотра
  glTranslatef (0.01f, -0.01f, 0.0f);
  glTranslatef (0.0f, 1.75f, -5.0f);
  glScalef (0.17f, 0.17f, 0.0f);
  glColor3f (0.1f, 0.1f, 0.1f);
  glPrint ("FPS:%d X:%d Y:%d", fps, posX, posY);// Печать текста GL на экран

  glLoadIdentity ();// Сброс просмотра
  glTranslatef (0.0f, 1.75f, -5.0f);
  glScalef (0.17f, 0.17f, 0.0f);
  glColor3f (1.0f, 0.5f, 0.0f);
  glPrint ("FPS:%d X:%d Y:%d", fps, posX, posY);// Печать текста GL на экран

  glColor3f (1.0f, 1.0f, 1.0f);
  glPrint ("   :%d  :%d  :%d", fps, posX, posY);// Печать текста GL на экран

  glColor3f (1.0f, 1.0f, 0.0f);
  glPrint ("    %d   %d   %d", fps, posX, posY);// Печать текста GL на экран

  glEnable (GL_DEPTH_TEST);// Включаем тест глубины
 }
}

void loading ()
{
 glPushMatrix ();
 glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity ();// Сброс просмотра
 glTranslatef (0.01f, -0.01f, 0.0f);
 glTranslatef (0.0f, -0.1f, -5.0f);
 glScalef (0.57f, 0.57f, 1.0f);
 glBindTexture (GL_TEXTURE_2D, texture [0]);
 // Позиционирование текста на экране
 glColor3f (0.1f, 0.1f, 0.1f);
 glPrint ("Загрузка...");// Печать текста GL на экран

 glLoadIdentity ();// Сброс просмотра
 glTranslatef (0.0f, -0.1f, -5.0f);
 glScalef (0.57f, 0.57f, 1.0f);
 // Позиционирование текста на экране
 glColor3f (1.0f, 1.0f, 0.0f);
 glPrint ("Загрузка...");// Печать текста GL на экран

 glPopMatrix ();
 SwapBuffers (hDC);
}

void saveConf()
{
 FILE *file;
 int i;
 char conf [1024];

 sprintf (conf, "Sound:%d\r\nMelody:%d\r\nAI:%d\r\n",
                sndVol, melVol, AI);
 char path [_MAX_PATH];
 sprintf (path, "%s%s", AppDir, "data\\config.txt");

 file=fopen (path, "wb");
 if (file!=NULL)
 {
  fwrite (conf, 1, strlen (conf), file);
  fclose (file);
 }
}

void loadConf ()
{
 FILE *file;
 int i, i2, n=0, n2, fS, confMx=1024, parMx=32, parL;
 char conf [1024], par [32], par0 [32], par1 [32];
 memset (conf, 0, confMx);

 char path [_MAX_PATH];
 sprintf (path, "%s%s", AppDir, "data\\config.txt");

 file=fopen (path, "rb");
 if (file!=NULL)
 {
  fseek (file, 0, SEEK_END);// seek to end of file
  fS=ftell (file);// get current file pointer
  fseek (file, 0, SEEK_SET);// seek to begin of file
  if (fS<confMx-2)
   fread (conf, 1, fS, file);
  else
   fread (conf, 1, confMx-2, file);
  fclose (file);
 }
 strcat (conf, "\n");

 for (i2=0; i2<strlen (conf); i2++)
 {
  if (conf [i2]!='\n' && conf [i2]!='\r')
   break;
 }
 n=i2;

 for (i=n; i<strlen (conf); i++)
 {
  if (conf [i]=='\n' || conf [i]=='\r')
  {
   memset (par, 0, parMx);
   for (i2=n; i2<i; i2++)
    par [i2-n]=conf [i2];

   for (i2=i+1; i2<strlen (conf); i2++)
   {
    if (conf [i2]!='\n' && conf [i2]!='\r')
     break;
   }
   n=i2;
   i=i2;

   parL=strlen (par);
   if (parL>parMx)
    parL=parMx;

   memset (par0, 0, parMx);
   memset (par1, 0, parMx);
   n2=0;
   for (i2=0; i2<parL; i2++)
   {
    if (par [i2]==':')
    {
     n2=i2;
     break;
    }
   }
   if (n2)
   {
    memcpy (par0, par, i2);
    for (i2=n2+1; i2<parL; i2++)
     par1 [i2-n2-1]=par [i2];
   }
   if (!strcmp (par0, "Sound"))
   {
    sndVol=atoi (par1);
    soundVol=sndVol*250;
    if (soundVol>1000)
     soundVol=1000;
    if (soundVol<0)
     soundVol=0;
    if (soundVol)
     soundOn=true;
    else
     soundOn=false;
   }
   else if (!strcmp (par0, "Melody"))
   {
    melVol=atoi (par1);
    meloVol=melVol*250;
    if (meloVol>1000)
     meloVol=1000;
    if (meloVol<0)
     meloVol=0;
    if (meloVol)
     meloIs=true;
    else
     meloIs=false;
   }
   else if (!strcmp (par0, "AI"))
   {
    AI=atoi (par1);
    if (AI!=0 && AI!=1 && AI!=2)
     AI=1;
   }
  }
 }
}