 
#include "stdio.h"
#include "assert.h"
#include "windows.h"
#include "math.h"
#include "Shared.h"

const int Size_nx = 59*32/4;
const int Size_ny = 576;

static DWORD* ImgFine = NULL;
static short* ImgFineY = NULL;
static short* ImgFineD = NULL;

static DWORD* PrevImg = NULL;
static DWORD* PrevImgFine = NULL;
static DWORD* PrevImgD = NULL;

static DWORD* ImgFine2 = NULL;
static short* ImgFine2Y = NULL;
static short* ImgFine2D = NULL;

static volatile int _Thread_FrameLine0 = 0;
static volatile int _Thread_FrameLine1 = 0;
static volatile int _Thread_Idle;
static volatile int _Thread_LineCnt;
static CRITICAL_SECTION _Thread_CritSection;
static HANDLE _Thread_hEvent[3] = { NULL };

extern DWORD TMO;

static int iImg = 8;
             
//################################################### CopyLine
static void CopyLine(TUSBItem_LineEx* Dest, TUSBItem_LineEx* Source)
{
  Dest->Odd        = Source->Odd;
  Dest->Adc2       = Source->Adc2;
  Dest->SubImageOfs= Source->SubImageOfs;
  Dest->BurstOk    = Source->BurstOk;
  Dest->BurstPhi   = Source->BurstPhi;
  Dest->y          = Source->y;
}

//################################################### SetSamples
static void SetSamples(TUSBItem_LineEx* Dest, TUSBItem_LineEx* Source)
{
  Dest->Samples = Dest->Samples==Dest->ADC1 ? Source->ADC1 :  Source->ADC2;
}

//################################################### LineProcFine
static void LineProcFine(int iFrame, int iLine)
{
  if(iLine-22>=0 && iLine-22<288 && (iFrame&1)==1)
  {

    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+0+0)&ImgMsk].Img+iLine;
    TUSBItem_LineEx* sl1 = ImgArr[(iFrame+0+1)&ImgMsk].Img+iLine;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame+4+0)&ImgMsk].Img+iLine;
    TUSBItem_LineEx* sl3 = ImgArr[(iFrame+4+1)&ImgMsk].Img+iLine;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line1;
    TUSBItem_LineEx  Line2;
    TUSBItem_LineEx  Line3;
    CopyLine(&Line0, sl0);
    CopyLine(&Line1, sl1);
    CopyLine(&Line2, sl2);
    CopyLine(&Line3, sl3);

    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line1, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      InitLine(&Line0, &Line3, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line1, sl1);
      SetSamples(&Line2, sl2);
      SetSamples(&Line3, sl3);
      if(iLine==100 && 1==2)
      {
        printf("%5i - %i%i%i%i - %5i %5i %5i\n",
               iFrame,
               Line0.Odd, // 0 oder 1
               Line1.Odd, // +0 (keine Änderung zu Line0->Odd erlaubt)
               Line2.Odd, // +0
               Line3.Odd, // +0
               int8_t((Line2.Phi-Line0.Phi)/256),  // 128 +-32 (-> 180°)
               int8_t((Line3.Phi-Line1.Phi)/256),  // 128 +-32 (-> 180°)
               int8_t((Line1.Phi-Line0.Phi)/256)); //  64 +-32 (-> 90°)
      }
      for(int iSample=0; iSample<_nSample; iSample++)
      {

        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);

        // Chroma
        double U = 0;
        double V = 0;
        LineToUV(&Line0, &Line1, &Line2, &Line3, Phi0, iSample, &U, &V);

        for(int iSub=0; iSub<2; iSub++)
        {
          // Luma
          TUSBItem_LineEx* DotLine0 = iSub==0 ? &Line0 : &Line1;
          TUSBItem_LineEx* DotLine2 = iSub==0 ? &Line2 : &Line3;
          double Y = 0;
          LineToY(DotLine0, DotLine2, Phi0, iSample, U, V, &Y);
          int xx = (iSample*_nSub+DotLine0->xSub)/4;
          int yy = DotLine0->y;
          if(xx>=0)
          {
            int p = yy*Size_nx+xx;
            int iY = int((Y-_State.RefBlank));
            int D = abs(iY-ImgFineY[p]);
            /*
            if(D>100)
            {
              U = 0;
              V = 0;
            }
            */
            DWORD RGB = YUV_to_RGB(Y-_State.RefBlank, U, V);
            ImgFine[p] = RGB;
            ImgFineY[p] = iY;
            ImgFineD[p] = D;
          }
        }
      }
    }
  }
}

//################################################### LineProcFine
static void LineProcFine2(int iFrame, int iLine)
{
  /*
  if(iLine-22>=0 && iLine-22<288-4 && (iFrame&0)==0)
  {
    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+1)&ImgMsk].Img+iLine;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame-7)&ImgMsk].Img+iLine;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line2;
    CopyLine(&Line0, sl0);
    CopyLine(&Line2, sl2);
    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line2, sl2);
      for(int iSample=0; iSample<_nSample; iSample++)
      {

        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);
        int xx = (iSample*_nSub+Line0.xSub)/4;
        int yy = Line0.y+2;
        if(xx>=0)
        {
          int p = yy*Size_nx+xx;
          int D = abs(Line0.Samples[iSample]-Line2.Samples[iSample])/2;
          ImgFine2Y[p] = 0;
          ImgFine2D[p] = D;
        }
      }
    }
  }
  if(iLine-22>=0 && iLine-22<288-4 && (iFrame&0)==0 && 1==2)
  {
    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+0+0)&ImgMsk].Img+iLine+1;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame+0+0)&ImgMsk].Img+iLine+3;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line2;
    CopyLine(&Line0, sl0);
    CopyLine(&Line2, sl2);
    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line2, sl2);
      for(int iSample=0; iSample<_nSample; iSample++)
      {

        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);
        int xx = (iSample*_nSub+Line0.xSub)/4;
        int yy = Line0.y+2;
        if(xx>=0)
        {
          int p = yy*Size_nx+xx;
          int iY = (Line0.Samples[iSample]+Line2.Samples[iSample])/2-_State.RefBlank;
          int D = abs(iY-ImgFineY[p]);
          ImgFine2Y[p] = iY/2;
          ImgFine2D[p] = D;
        }
      }
    }
  }
  */
  if(iLine-22>=0 && iLine-22<288-4 && (iFrame&1)==1)
  {
    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+0+0)&ImgMsk].Img+iLine+1;
    TUSBItem_LineEx* sl1 = ImgArr[(iFrame+0+1)&ImgMsk].Img+iLine+1;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame+0+0)&ImgMsk].Img+iLine+3;
    TUSBItem_LineEx* sl3 = ImgArr[(iFrame+0+1)&ImgMsk].Img+iLine+3;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line1;
    TUSBItem_LineEx  Line2;
    TUSBItem_LineEx  Line3;
    CopyLine(&Line0, sl0);
    CopyLine(&Line1, sl1);
    CopyLine(&Line2, sl2);
    CopyLine(&Line3, sl3);
    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line1, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      InitLine(&Line0, &Line3, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line1, sl1);
      SetSamples(&Line2, sl2);
      SetSamples(&Line3, sl3);
      if(iLine==100 && 1==2)
      {
        printf("%5i - %i%i%i%i - %5i %5i %5i\n",
               iFrame,
               Line0.Odd, // 0 oder 1
               Line1.Odd, // +0 (keine Änderung zu Line0->Odd erlaubt)
               Line2.Odd, // +0
               Line3.Odd, // +0
               int8_t((Line2.Phi-Line0.Phi)/256),  // 128 +-32 (-> 180°)
               int8_t((Line3.Phi-Line1.Phi)/256),  // 128 +-32 (-> 180°)
               int8_t((Line1.Phi-Line0.Phi)/256)); //  64 +-32 (-> 90°)
      }
      for(int iSample=0; iSample<_nSample; iSample++)
      {

        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);

        // Chroma
        double U = 0;
        double V = 0;
        LineToUV(&Line0, &Line1, &Line2, &Line3, Phi0, iSample, &U, &V);
        for(int iSub=0; iSub<2; iSub++)
        {
          // Luma
          TUSBItem_LineEx* DotLine0 = iSub==0 ? &Line0 : &Line1;
          TUSBItem_LineEx* DotLine2 = iSub==0 ? &Line2 : &Line3;
          double Y = 0;
          LineToY(DotLine0, DotLine2, Phi0, iSample, U, V, &Y);
          int xx = (iSample*_nSub+DotLine0->xSub)/4;
          int yy = DotLine0->y+2;
          if(xx>=0)
          {
            int p = yy*Size_nx+xx;
            int iY = int((Y-_State.RefBlank));
            int D = abs(iY-ImgFineY[p]);
            /*
            if(D>100)
            {
              U = 0;
              V = 0;
            }
            */
            DWORD RGB = YUV_to_RGB(Y-_State.RefBlank, U, V);
            ImgFine2[p] = RGB;
if(iSub==1 && D>-10 && 1==1)
{
  // printf("%i ", xx&1);
  ImgFine2[p+2] = RGB;
  ImgFine2[Size_nx+p+1] = RGB;
}
            ImgFine2Y[p] = iY;
            ImgFine2D[p] = D;
          }
        }
      }
    }
  }
}

/*

//################################################### LineToUV
static void xLineToUV(TUSBItem_LineEx* Line0,
                      TUSBItem_LineEx* Line1,
                      TUSBItem_LineEx* Line2,
                      TUSBItem_LineEx* Line3,
                      TUSBItem_LineEx* Line4,
                      TUSBItem_LineEx* Line5,
                      uint16_t Phi0,
                      uint16_t iSample,
                      double*  ResY,
                      double*  ResU,
                      double*  ResV,
                      double*  ResD)
{
  uint16_t p0 = Phi0+Line0->Phi;
  uint16_t p1 = Phi0+Line1->Phi;
  uint16_t p2 = Phi0+Line2->Phi;

int Y0 = 1*(Line5->Samples[iSample]+Line1->Samples[iSample])/2;
int Y1 = 1*(Line0->Samples[iSample]+Line2->Samples[iSample])/2;
int Y2 = 1*(Line2->Samples[iSample]+Line4->Samples[iSample])/2;
Y0=0; Y1=0; Y2=0; 


  double c0 = cos16(p0);
  double c1 = cos16(p1);
  double c2 = cos16(p2);
  double s0 = sin16(p0);
  double s1 = sin16(p1);
  double s2 = sin16(p2);
  double a = 1;
  double b = s0;
  double c = c0*(Line0->Odd ? -1 : +1);
  double d = -(Line0->Samples[iSample]-Y0);
  double l = 1;
  double m = s1;
  double n = c1*(Line1->Odd ? -1 : +1);
  double k = -(Line1->Samples[iSample]-Y1);
  double p = 1;
  double q = s2;
  double r = c2*(Line2->Odd ? -1 : +1);
  double s = -(Line2->Samples[iSample]-Y2);
  double D = (a*m*r+b*p*n+c*l*q)-(a*n*q+b*l*r+c*m*p);
  *ResD = fabs(D);
  if(fabs(D)<.004)
  {
    *ResU = 0;
    *ResV = 0;
    return;
  }
  *ResY = ((b*r*k+c*m*s+d*n*q)-(b*n*s+c*q*k+d*m*r))/D;
  *ResU = ((a*n*s+c*p*k+d*l*r)-(a*r*k+c*l*s+d*n*p))/D;
  *ResV = ((a*q*k+b*l*s+d*m*p)-(a*m*s+b*p*k+d*l*q))/D;
}

//################################################### LineProcFine
static void LineProcRaw(int iFrame, int iLine)
{
  if(iLine-22>=0 && iLine-22<288 && (iFrame&0)==0)
  {
    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine-1;
    TUSBItem_LineEx* sl1 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine+0;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine+1;
    TUSBItem_LineEx* sl3 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine+2;
    TUSBItem_LineEx* sl4 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine+3;
    TUSBItem_LineEx* sl5 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine-2;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line1;
    TUSBItem_LineEx  Line2;
    TUSBItem_LineEx  Line3;
    TUSBItem_LineEx  Line4;
    TUSBItem_LineEx  Line5;
    CopyLine(&Line0, sl0);
    CopyLine(&Line1, sl1);
    CopyLine(&Line2, sl2);
    CopyLine(&Line3, sl3);
    CopyLine(&Line4, sl4);
    CopyLine(&Line5, sl5);
    double UArr[2][_nSample];
    double VArr[2][_nSample];
    double DArr[2][_nSample];
    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line1, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      InitLine(&Line0, &Line3, dADC, dADC);
      InitLine(&Line0, &Line4, dADC, dADC);
      InitLine(&Line0, &Line5, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line1, sl1);
      SetSamples(&Line2, sl2);
      SetSamples(&Line3, sl3);
      SetSamples(&Line4, sl4);
      SetSamples(&Line5, sl5);
      for(int iSample=0; iSample<_nSample; iSample++)
      {
        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);

        // Chroma
        double Y = 0;
        double U = 0;
        double V = 0;
        double D = 0;
        xLineToUV(&Line0,
                  &Line1,
                  &Line2,
                  &Line3,
                  &Line4,
                  &Line5,
                  Phi0,
                  iSample,
                  &Y,
                  &U,
                  &V,
                  &D);
// U = (Line0.Samples[iSample]+Line2.Samples[iSample])/2;
        UArr[iADC][iSample] = U;
        VArr[iADC][iSample] = V;
        DArr[iADC][iSample] = D;
      }
    }

    int   xArr[2*70];
    DWORD vArr[2*70];
    int yy;
    for(iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      yy = Line0.y;
      InitLine(&Line0, &Line0, dADC, dADC);
      SetSamples(&Line0, sl0);
      for(int iSample=0; iSample<_nSample; iSample++)
      {
        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);

        // Chroma
        int ii = DArr[0][iSample]<DArr[1][iSample] ? 1 : 0;
        double sY = 0;
        double sU = UArr[ii][iSample];
        double sV = VArr[ii][iSample];
        static double PrevU[2][160];
        static double PrevV[2][160];
// sU = (sU+PrevU[iADC][iSample])/2;
// sV = (sV+PrevV[iADC][iSample])/2;
        PrevU[iADC][iSample] = UArr[ii][iSample];
        PrevV[iADC][iSample] = VArr[ii][iSample];
   
        LineToY(&Line0 , NULL, Phi0, iSample, sU, sV, &sY);
// sY = sU;sU = 0;sV = 0;
        DWORD sRGB = YUV_to_RGB(sY-_State.RefBlank, sU, sV);
        xArr[2*iSample+1-iADC] = (iSample*_nSub+Line0.xSub)/4;
        vArr[2*iSample+1-iADC] = sRGB;
      }
    }
    for(int iSample=0; iSample<2*_nSample-1; iSample++)
    {
      int xx0 = xArr[iSample+0];
      int xx1 = xArr[iSample+1];
      if(xx0<0) continue;
      if(yy<1 || yy>=Size_ny) continue;
      BYTE* q00 = (BYTE*)(&PrevImg[yy*Size_nx+xx0]);
      BYTE* q01 = (BYTE*)(&PrevImg[yy*Size_nx+xx1]);
      BYTE* q10 = (BYTE*)(&vArr[iSample+0]);
      BYTE* q11 = (BYTE*)(&vArr[iSample+1]);
      int d0 = abs(q10[0]-q00[0])+abs(q10[1]-q00[1])+abs(q10[2]-q00[2]);
      int d1 = abs(q11[0]-q01[0])+abs(q11[1]-q01[1])+abs(q11[2]-q01[2]);
      d0 = abs((q10[0]+q10[1]+q10[2])-(q00[0]+q00[1]+q00[2]));
      d1 = abs((q11[0]+q11[1]+q11[2])-(q01[0]+q01[1]+q01[2]));
      int d = d0<d1 ? d0 : d1;
      d = (d0+d1)/3;
      d = 3*d/2;
      // d = d>40 ? 255 : 0;
      if(d<0) d=0;
      if(d>255) d=255;
      /*
      PrevImg[yc*Size_nx+xx0] = vArr[iSample+0];
      DWORD RGB = d|(d<<8)|(d<<16);
      Blit->SetPixel(xx0, yy+0, RGB);
      Blit->SetPixel(xx0, yy+1, RGB);
      */
      //d = (d0+d1)/2;
      // d =0;
      // d = 120;
      //d = d<100  ? 0 : 255;
/*      d = d; // -100;
      if(d<0) d=0;
      if(d>255) d=255;
      // d =255;
      // DWORD RGB = *(DWORD*)q10;
      // 144c 81 423
      for(int x=xx0+1; x<xx1; x++)
      {
        int dn = xx1-xx0+1;
        DWORD RGB = 0;
        BYTE* z = (BYTE*)&RGB;
        BYTE* q = (BYTE*)(&PrevImg[yy*Size_nx+x]);
        for(int i=0; i<3; i++)
        {
          BYTE v0 = q[i];
          int v1 = q10[i]+(x-xx0)*(int(q11[i])-q10[i])/dn;
          int v = (v0*(255-d)+v1*d)/255;
          z[i] = v;
        }
        PrevImg[yy*Size_nx+x] = RGB;
        // PrevImg[(yy-1)*Size_nx+x] = RGB;
        // Blit->SetPixel(x, yy+0, RGB);
        // Blit->SetPixel(x, yy+1, RGB);
      }
    }
    for(iSample=0; iSample<2*_nSample; iSample++)
    {
      int x = xArr[iSample];
      if(x<0) continue;
      if(yy<1 || yy>=Size_ny) continue;
      DWORD RGB = vArr[iSample];
      PrevImg[yy*Size_nx+x] = RGB;
      // PrevImg[(yy-1)*Size_nx+x] = RGB;
    }
  }
}
  */

/*
//################################################### LineProcFine2
static void LineProcRaw2(int iFrame, int iLine)
{
  if(iLine-22>=2 && iLine-22<288 && (iFrame&0)==0)
  {
    TUSBItem_LineEx* sl0 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine-1;
    TUSBItem_LineEx* sl2 = ImgArr[(iFrame+0)&ImgMsk].Img+iLine+1;
    TUSBItem_LineEx  Line0;
    TUSBItem_LineEx  Line2;
    CopyLine(&Line0, sl0);
    CopyLine(&Line2, sl2);
    for(int iADC=0; iADC<2; iADC++)
    {
      int dADC = iADC*_Config.dADC2;
      InitLine(&Line0, &Line0, dADC, dADC);
      InitLine(&Line0, &Line2, dADC, dADC);
      SetSamples(&Line0, sl0);
      SetSamples(&Line2, sl2);
      for(int iSample=0; iSample<_nSample; iSample++)
      {
        int dxColor = _ImageOfs0+_ImageOfs+iSample*_nSub;
        uint16_t Phi0 = uint16_t(dxColor/1e6/_fADCMHz*fPAL*(1+_dPPM_PAL*1e-6)*65536);
        Phi0 += uint16_t(65536*_dphiColor_degree/360);

        int Y = (Line0.Samples[iSample]+Line2.Samples[iSample])/2;
        Y = Y-_State.RefBlank;
// Y = Y-2*abs(Line0.Samples[iSample]-Line2.Samples[iSample]);

        if(Y<0) Y=0; 
        int x = (iSample*_nSub+Line0.xSub)/4;
        int da = abs(Y-PrevImg[Line0.y*Size_nx+x]);
        PrevImg[Line0.y*Size_nx+x] = Y;
        PrevImgD[Line0.y*Size_nx+x] = da;
      }
    }
  }
}
  */


//################################################### ThreadFunc
static DWORD WINAPI ThreadFunc(void* Param)
{
  int iProc = (int)Param;
  while(true)
  {
    int iFrame = 0;
    int iLine  = -1;
    EnterCriticalSection(&_Thread_CritSection);
    if(_Thread_FrameLine0!=_Thread_FrameLine1)
    {
      iFrame = _Thread_FrameLine0/512;
      iLine  = _Thread_FrameLine0&0x1ff;
      _Thread_FrameLine0++;
      if(iLine==340)
      {
        _Thread_FrameLine0 = ((_Thread_FrameLine0/512)+1)*512;
      }
      _Thread_FrameLine0 = _Thread_FrameLine0&((ImgMsk+1)*512-1);
    }
    if(_TotalLine<=1125)
    {
     printf("*");
      _Thread_FrameLine0=_Thread_FrameLine1;
    }
    LeaveCriticalSection(&_Thread_CritSection);
    if(iLine<0)
    {
      EnterCriticalSection(&_Thread_CritSection);
      _Thread_Idle++;
      SetEvent(_Thread_hEvent[2]);
      LeaveCriticalSection(&_Thread_CritSection);
      WaitForSingleObject(_Thread_hEvent[iProc], INFINITE);
      EnterCriticalSection(&_Thread_CritSection);
      _Thread_Idle--;
      LeaveCriticalSection(&_Thread_CritSection);
    }
    if(iLine>=0)
    {
      EnterCriticalSection(&_Thread_CritSection);
      _Thread_LineCnt++;
      // printf("*");
      LeaveCriticalSection(&_Thread_CritSection);
      LineProcFine(iFrame, iLine);
      /*
      if(iImg==2)
      // LineProcRaw(iFrame, iLine);
      else
      */
      {
        // LineProcRaw2(iFrame, iLine);
        LineProcFine2(iFrame, iLine);
      }
    }
  }
  return 0;
}

//################################################### Mode6_ProcessLine
void Mode6_ProcessLine(TUSBItem_Line* USBItem)
{
  if(Blit==NULL)
  {
    // Blit
    int bSize_nx = 59*32/4;
    int bSize_ny = 576-3;
    Blit = new TBlit(bSize_nx,
                     bSize_ny, "0.04 s",
                     bSize_nx*2,
                     bSize_ny*1);
    // Mem
    ImgFine  = (DWORD*)malloc(Size_nx*Size_ny*4);
    ImgFineY = (short*)malloc(Size_nx*Size_ny*2);
    ImgFineD = (short*)malloc(Size_nx*Size_ny*2);
    PrevImg = (DWORD*)malloc(Size_nx*625*4);
    PrevImgD = (DWORD*)malloc(Size_nx*625*4);
    PrevImgFine = (DWORD*)malloc(Size_nx*625*4);
    ImgFine2  = (DWORD*)malloc(Size_nx*Size_ny*4);
    ImgFine2Y = (short*)malloc(Size_nx*Size_ny*2);
    ImgFine2D = (short*)malloc(Size_nx*Size_ny*2);
    // Thread
    InitializeCriticalSection(&_Thread_CritSection);
    _Thread_hEvent[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
    for(int i=0; i<2; i++)
    {
      DWORD ThreadID;
      _Thread_hEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
      HANDLE HThread = CreateThread(NULL,
                                    0,
                                    ThreadFunc,
                                    (void*)i,
                                    0,
                                    &ThreadID);
    }
  }

  int iFrame = _State.VSyncCnt&ImgMsk;

  AddToImgArr(USBItem, iFrame);

  int iLine = _iLine;

  iFrame = (iFrame-5)&ImgMsk;

  // Fine - Slow
  if(_Thread_hEvent[0]==NULL)
  {
    LineProcFine(iFrame, iLine);
  }

  // Raw - Fast 
  if(_Thread_hEvent[1]==NULL)
  {
    // LineProcRaw(iFrame, iLine);
  }

  if(iLine==20 && (_State.VSyncCnt&1)==1 && 1==1)
  {
    __asm rdtsc
    __asm sub TMO,eax
    __asm rdtsc
    __asm add TMO,eax
    // if(_Thread_Busy[0] || _Thread_Busy[1]) printf("*"); else printf(".");
    //  while(_Thread_Idle!=2) Sleep(1);
    if(_Thread_hEvent[0]!=NULL)
    {
      EnterCriticalSection(&_Thread_CritSection);
      ResetEvent(_Thread_hEvent[2]);
      bool Wait = _Thread_FrameLine0!=_Thread_FrameLine1;
      LeaveCriticalSection(&_Thread_CritSection);
      if(Wait)
      {
        WaitForSingleObject(_Thread_hEvent[2], INFINITE);
        printf("*");
      }
    }
  //  _Thread_FrameLine1 = iFrame*512+iLine;
//    _Thread_FrameLine0 = _Thread_FrameLine1;
//   Sleep(1);
//  printf("%i ", _Thread_Idle);
    static DWORD TMPA=0;
    static DWORD TMPB=0;
    __asm rdtsc
    __asm mov TMPB, eax
    // printf("%3i %5i  %5i - %8i\n", _Thread_Idle, _Thread_LineCnt, _Thread_FrameLine0&0x1ff, (TMPB-TMPA)/2100);
    // printf("%i ", _Thread_LineCnt);
    __asm rdtsc
    __asm mov TMPA, eax
    // Sleep(10);
    _Thread_LineCnt = 0;
    char c = 'a'+iImg;
    //  = GetAsyncKeyState(VK_SHIFT)!=0;
    if(GetAsyncKeyState(VK_LEFT )!=0) iImg=2;
    if(GetAsyncKeyState(VK_RIGHT)!=0) iImg=8;
    for(int y=1; y<Size_ny; y++)
    {
      for(int x=((y&1)^1); x<Size_nx; x+=2)
      {
        // Fine
        if(iImg==5)
        { 
          int d0 = (PrevImg[y*Size_nx+x]+PrevImg[(y+2)*Size_nx+x])/2;
          int d1 = d0; // (PrevImg[(y+4)*Size_nx+x]+PrevImg[(y+6)*Size_nx+x])/2;
          int d = (d0+d1)/2;
          d = PrevImg[y*Size_nx+x];
          if(d<0) d=0;
          if(d>255) d=255;
          DWORD RGB = d|(d<<8)|(d<<16);
          Blit->SetPixel(x, y-0, RGB);
          Blit->SetPixel(x+1, y-0, RGB);
          /*
          // int d = ImgFineY[y*Size_nx+x];
          int d = PrevImg[y*Size_nx+x];
          if(d<0) d=0;
          if(d>255) d=255;
          DWORD RGB = d|(d<<8)|(d<<16);
          Blit->SetPixel(x, y-0, RGB);
          // Blit->SetPixel(x, y-1, RGB);
          d = (PrevImg[y*Size_nx+x]+PrevImg[y*Size_nx+x+2])/2;
          if(d<0) d=0;
          if(d>255) d=255;
          RGB = d|(d<<8)|(d<<16);
          Blit->SetPixel(x+1, y-0, RGB);
          */
        }
        if(iImg==0)
        {
          BYTE* RGB0 = (BYTE*)&ImgFine[y*Size_nx+x+0];
          BYTE* RGB1 = (BYTE*)&ImgFine[y*Size_nx+x+2];
          BYTE* RGB2 = (BYTE*)&ImgFine[(y-1)*Size_nx+x+1];
          BYTE* RGB3 = (BYTE*)&ImgFine[(y+1)*Size_nx+x+1];
          Blit->SetPixel(x+0, y-0, *(DWORD*)RGB0);
          Blit->SetPixel(x+0, y-1, *(DWORD*)RGB0);
          BYTE Tmp[4];
          Tmp[0] = (RGB0[0]+RGB1[0]+RGB2[0]+RGB3[0])/4;
          Tmp[1] = (RGB0[1]+RGB1[1]+RGB2[1]+RGB3[1])/4;
          Tmp[2] = (RGB0[2]+RGB1[2]+RGB2[2]+RGB3[2])/4;
          // Blit->SetPixel(x+0, y-1, *(DWORD*)RGB2);
          // Blit->SetPixel(x+1, y, *(DWORD*)Tmp);
        }
        // Fine2
        if(iImg==6)
        {
          BYTE* RGB0 = (BYTE*)&ImgFine2[y*Size_nx+x+0];
          BYTE* RGB1 = (BYTE*)&ImgFine2[y*Size_nx+x+2];
          BYTE* RGB2 = (BYTE*)&ImgFine2[(y-1)*Size_nx+x+1];
          BYTE* RGB3 = (BYTE*)&ImgFine2[(y+1)*Size_nx+x+1];
          Blit->SetPixel(x+0, y-0, *(DWORD*)RGB0);
          Blit->SetPixel(x+0, y-1, *(DWORD*)RGB0);
          BYTE Tmp[4];
          Tmp[0] = (RGB0[0]+RGB1[0]+RGB2[0]+RGB3[0])/4;
          Tmp[1] = (RGB0[1]+RGB1[1]+RGB2[1]+RGB3[1])/4;
          Tmp[2] = (RGB0[2]+RGB1[2]+RGB2[2]+RGB3[2])/4;
          // Blit->SetPixel(x+1, y, *(DWORD*)Tmp);
        }
        // dFine2
        if(iImg==7)
        {
          // int d = ImgFineY[y*Size_nx+x]/8;
          // int d = ImgFine2Y[y*Size_nx+x]/4; c='k';
          int d = ImgFine2D[y*Size_nx+x]/2; c='k';
          // int d = PrevImg[y*Size_nx+x]/6;
          // int d = PrevImgD[y*Size_nx+x]/5; c = 'k';
          
          
          if(d<0) d=0;
          if(d>255) d=255;
          DWORD RGB = d|(d<<8)|(d<<16);
          Blit->SetPixel(x, y-0, RGB);
          Blit->SetPixel(x, y-1, RGB);
        }
        if(iImg==8)
        {
          BYTE* q0 = (BYTE*)&ImgFine[y*Size_nx+x+0];
          BYTE* q1 = (BYTE*)&ImgFine2[y*Size_nx+x+0];
          DWORD RGB = 0;
          BYTE* z = (BYTE*)&RGB;
          int d0 = ImgFineD[y*Size_nx+x-2];
          int d1 = ImgFineD[y*Size_nx+x+0];
          int d2 = ImgFineD[y*Size_nx+x+2];
          int d3 = ImgFineD[(y-1)*Size_nx+x+1];
          int d4 = ImgFineD[(y+1)*Size_nx+x+1];
          int d = (d0+d1+d2+d3+d4)*1-300;
          // d = ImgFineD[y*Size_nx+x+0];
          if(d<0) d=0;
          if(d>255) d=255;
          // d = 255*1;
          // c = 'b';
          for(int i=0; i<3; i++)
          {
            z[i] = (d*q1[i]+(255-d)*q0[i])/255;
            // z[i] = (d*0+(255-d)*q0[i])/255;
            // z[i] = (d*q1[i]+(255-d)*0)/255;
            // z[i] = d;
          }
          Blit->SetPixel(x+0, y-0, RGB);
          Blit->SetPixel(x+0, y-1, RGB);
        }
        // dFine
        if(iImg==1)
        {
          // int d = ImgFineY[y*Size_nx+x];
          int d = ImgFineD[y*Size_nx+x]/2;
          for(int dx=0; dx<8; dx++)
          {
            int dc = ImgFineD[(y+(dx&1))*Size_nx+x+dx]/2;
            if(dc<d) d=dc;
          }
          if(d<0) d=0;
          if(d>255) d=255;
          DWORD RGB = d|(d<<8)|(d<<16);
          Blit->SetPixel(x, y-0, RGB);
          Blit->SetPixel(x, y-1, RGB);
        }
        if(iImg==2)
        {
          BYTE* q0 = (BYTE*)&ImgFine[y*Size_nx+x+0];
          BYTE* q1 = (BYTE*)&PrevImg[y*Size_nx+x+0];
          DWORD RGB = 0;
          BYTE* z = (BYTE*)&RGB;
          int d0 = ImgFineD[y*Size_nx+x-2];
          int d1 = ImgFineD[y*Size_nx+x+0];
          int d2 = ImgFineD[y*Size_nx+x+2];
          int d3 = ImgFineD[(y-1)*Size_nx+x+1];
          int d4 = ImgFineD[(y+1)*Size_nx+x+1];
          int d = (d0+d1+d2+d3+d4)*1-300;
          if(d<0) d=0;
          if(d>255) d=255;
          // d = 255*1;
          // c = 'b';
          for(int i=0; i<3; i++)
          {
            z[i] = (d*q1[i]+(255-d)*q0[i])/255;
            // z[i] = (d*0+(255-d)*q0[i])/255;
            // z[i] = (d*q1[i]+(255-d)*0)/255;
          }
          Blit->SetPixel(x+0, y-0, RGB);
          Blit->SetPixel(x+1, y-0, RGB);
        }
      }
    }
    // ZeroMemory(ImgFine2, Size_nx*Size_ny*4);
    EnterCriticalSection(&_Thread_CritSection);
    _Thread_FrameLine1 = iFrame*512+iLine;
    LeaveCriticalSection(&_Thread_CritSection);
    SetEvent(_Thread_hEvent[0]);
    SetEvent(_Thread_hEvent[1]);

    Blit->DoBlit();
    char TmpFileName[MAX_PATH];
    sprintf(TmpFileName, "s:\\1\\%%04i%c.bmp", c);
    // Blit->SaveImg(TmpFileName);
  }
}
