#include "complex.h"
#include "gr_def.h"
#include "screen.h"

extern byte FastFill;

typedef struct pcxheader {
        char     manuf;                 /* Always =10 for Paintbrush   */
        char     hard;                  /* Version information         */
        char     encod;                 /* Run-length encoding (=1)    */
        char     bitpx;                 /* Bits per pixel              */
        word     x1;                    /* Picture dimensions (incl)   */
        word     y1;
        word     x2;
        word     y2;
        word     hres;                  /* Display horiz resolution    */
        word     vres;                  /* Display vert  resolution    */
        byte     clrma[48];             /* Pallete                     */
        char     vmode;                 /* (ignored)                   */
        char     nplanes;               /* Number of planes (ver 2.5=0)*/
        word     bplin;                 /* Bytes per line              */
        word     palinfo;               /* Palette Info (1=col, 2=gray)*/
        word     shres;                 /* Scanner resolution          */
        word     svres;                 /*                             */
        char     xtra[54];              /* Extra space (filler)        */
} PCXHEADER;

typedef struct pcxlibdir {
        char         synch;                 /* Synch byte                  */
        char         filename[13];          /* Image file name             */
        long         filesize;              /* File size                   */
        word     date;                  /* File date                   */
        word     time;                  /* File time                   */
        word     pack;                  /* Packing type                */
        char         note[40];              /* Image note                  */
        char         xtra[20];              /* Extra filler                */
} PCXLIBDIR;

typedef struct pcxlibheader {
        char         id[10];                /* Library ID string           */
        char         copyright[50];         /* Copyright notice            */
        word     version;               /* pcxLib version              */
        char         label[40];             /* Library volume label        */
        char         xtra[20];              /* filler                      */
} PCXLIBHEADER;

long flib_len;
PCXLIBHEADER * lib_prt;

word_s tol;

struct viewporttype vpA;
struct fillsettingstype fiA={0,1},fiT;
struct linesettingstype lsN={-1,0,1},lsP,lsA={-1,0,1},lsT;



typedef struct tagBITMAPFILEHEADER {
        word    bfType;         //тип файла (для битового образа - BM)
        dword   bfSize;         //размер файла в dword
        word    bfReserved1;    //не используется
        word    bfReserved2;    //не используется
        dword   bfOffbits;      //смещение данных битового образа от
                                //заголовка в байтах
    }BITMAPFILEHEADER;

typedef struct tagRGBQUAD {
        byte    rgbRed;         //интенсивность красного
        byte    rgbGreen;       //интенсивность зеленого
        byte    rgbBlue;        //интенсивность голубого
        byte    rgbRserved;     //не используется
        } RGBQUAD;


typedef struct tagBITMAPINFOHEADER {
        dword   biSize;         //число байт, занимаемых структурой
                                //BITMAPINFOHEADER
        dword   biWidth;        //ширина битового образа в пикселах
        dword   biHeight;       //высота битового образа в пикселах
        word    biPlanes;       //число битовых плоскостей устройства
        word    biBitCount;     //число битов на пиксель
        dword   biCompression;  //тип сжатия
        dword   biSizeImage;    //размер картинки в байтах
        dword   biXPelsPerMeter;//горизонтальное разрешение устройства,
                                //пиксел/м
        dword   biYPelPerMeter; //вертикальное разрешение устройства,
                                //пиксел/м
        dword   biClrUsed;      //число используемых цветов
        dword   biClrImportant; //число "важных" цветов
    } BITMAPINFOHEADER;

void pcx_asm(word, word, unsigned char *);
#pragma aux pcx_asm = "      movzx  esi,dx                 "\
                      "      mov  ah,1                     "\
                      "      mov  dx,3c4h                  "\
                      "pln:  mov  al,2                     "\
                      "      out  dx,al                    "\
                      "      inc  dx                       "\
                      "      mov  al,ah                    "\
                      "      out  dx,al                    "\
                      "      dec  dx                       "\
                      "      movzx  ecx,bx                 "\
                      "      push esi                      "\
                      "      push ebx                      "\
                      "      mov  ebx,0A0000h              "\
                      "lin:  mov  al,[edi]                 "\
                      "      mov  [esi+ebx],al             "\
                      "      inc  esi                      "\
                      "      inc  edi                      "\
                      "      loop lin                      "\
                      "      pop  ebx                      "\
                      "      pop  esi                      "\
                      "      shl  ah,1                     "\
                      "      test ah,10h                   "\
                      "      jz   pln                      "\
                             modify [eax esi ecx]           \
                             parm [edx] [ebx] [edi]          ;

word_s setpcxvideo(char *flpcx,word x_video,word y_video, word xv)
{
  int hn;
  word f_len;
  PCXHEADER *pp;

  hn=open(flpcx,O_BINARY | O_RDWR);
  if(hn==-1) return (-1);

  f_len=(word)filelength(hn);
  pp=(PCXHEADER *)malloc(f_len);
  read(hn,pp,f_len);
  close(hn);

  DisplayBufPcx(pp,f_len,x_video,y_video,xv);

  free(pp);
  return (0);
}

void loadpcxlib(char *flpcl)
{
  int hn;

  hn=open(flpcl,O_BINARY | O_RDWR);
  if(hn==-1){flib_len=0; return ;}
  flib_len=(long)filelength(hn);
  lib_prt=(PCXLIBHEADER *)malloc(flib_len);
  read(hn,lib_prt,flib_len);
  close(hn);
}

word_s pcxDisplayLib(char *flpcx,word x_video,word y_video, word xv)
{
 word i,j,len_pcx;
 PCXLIBDIR * file_prt;
 char str[13];

 file_prt=(PCXLIBDIR *)(lib_prt+1);
 for(i=0,j=0;i<13 && flpcx[i]!=0;i++) if(flpcx[i]!=' '){flpcx[j]=flpcx[i]; j++;}
 flpcx[j]=0;
next_file:
 strncpy(str,file_prt->filename,13);
 for(i=0,j=0;i<13 && str[i]!=0;i++) if(str[i]!=' '){str[j]=str[i]; j++;}
 str[j]=0;

 if(strcmp(flpcx,str))
 {
  if(file_prt < (PCXLIBDIR *)((byte *)lib_prt+flib_len))                                    //!
  {
   file_prt = (PCXLIBDIR *)((byte *)file_prt+file_prt->filesize+sizeof(PCXLIBDIR));          //!
   goto next_file;
  };
  return (-1);
 }

 len_pcx=file_prt->filesize;
 file_prt=(PCXLIBDIR *) ((byte *)file_prt+sizeof(PCXLIBDIR));                                       //!
 DisplayBufPcx((PCXHEADER *)file_prt,len_pcx,x_video,y_video,xv);
 return (0);
}


void DisplayBufPcx(PCXHEADER *pp,word f_len,word x_video,word y_video, word xv )
{
  byte bt;
  word l_str,l_buf_str,sii,i,k;
  unsigned char *p_buf_str,*p_buf_fil, *pc;;

  l_str=pp->bplin;
  l_buf_str=l_str<<2;
  p_buf_str=(char *)malloc(l_buf_str+64);
  f_len-=0x80;
  p_buf_fil=(unsigned char *)(pp+1);

  outp(0x3ce,5);
  outp(0x3cf,0);
  outp(0x3ce,8);
  outp(0x3cf,0xff);

  sii=y_video*(xv/8)+x_video/8;
  k=0; pc=p_buf_str;
  for(i=0; i<f_len; )
  {
    bt=*p_buf_fil; p_buf_fil++; i++;
    if(bt > 0xC0)
    {
      bt &= 0x3f;
      memset(pc,*p_buf_fil,bt);
      k+=bt; pc+=bt;
      p_buf_fil++; i++;
    }
    else { *pc++=bt; k++; }

    if(k>=l_buf_str)
    {

     pcx_asm(sii,l_str,p_buf_str);
     sii+=xv/8;
     k-=l_buf_str;
     pc=p_buf_str+l_buf_str;
     memcpy(p_buf_str,pc,k);
     pc=p_buf_str+k;
    }
  }
  outp(0x3cf,0xff);                           /* восст.маски битов */
  outp(0x3c5,15);                             /* маска каpт - все */

  free(p_buf_str);
}
//**********************************************************************
unsigned char fill[]={
                           0,    0,    0,    0,    0,    0,    0,    0,
                        0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,

                        0377,    0,    0, 0377, 0377,    0,    0, 0377,
                          04,  010,  020,  040, 0100, 0200,    1,    2,
                        0203,   07,  016,  034,  070, 0160, 0340, 0301,
                        0360, 0270,  074,  036,  017, 0207, 0303, 0341,
                        0245, 0322, 0151, 0264, 0132,  055, 0226, 0113,
                         021,  021,  021, 0377,  021,  021,  021, 0377,
                        0204, 0110,  060,  060, 0110, 0204,   03,   03,
                        0146, 0231, 0146, 0231, 0146, 0231, 0146, 0231,
                           0,    1,    0,    2,    0,    1,    0,    2,
                           0, 0104,    0, 0104,    0, 0104,    0, 0104};


//---------------------------------------
void ch_color(int x,int y, int color)
{
 int y1, y2, x2, x1;
 int color1, color2;   // текущий цвет  и динамический
 int l=1;              // "1" - вправо от оси, "-1" - влево от оси
 int k=0;              // "0" - вертекальная ось, "1" - горизонтальная
 int i=0;              // счетчик

 if(!FastFill)
 {
   if((color1=_getpixel(x,y))==color) return;  // Если текущщий цвет равен устонавливаемому то выход
   _setcolor(color);

   x1=x; y1=y;
   mi2:;

   do
   {
     x1=x1-1;
     x2=x1;
     y2=y1;
     if(k==1)
     {
       x2=y1;
       y2=x1;
     };
     color2=_getpixel(x2,y2);
   } while(color2==color || color2==color1);

   mi3:
   ++x1;

   mi1:
   y1=y+(i*l);
   x2=x1;y2=y1;
   if(k==1) {y1=x+(i*l); x2=y1; y2=x1;};
   color2=_getpixel(x2,y2);
   ++i;
   if(color2==color1)
   {
     //  putpix(color,x2,y2);
     _setpixel(x2,y2);
     goto mi1;
   }
   if(color2==color) goto mi1;

   if(i==1)
   {
     if(k==1) return;
     k=1; i=0; l=1;
     x1=y; y1=x;
     goto mi2;
   }
   if(l==-1) {l=1;i=0;goto mi3;}
   l=-1;
   i=0;
   goto mi1;
 }
 else
 {
  if(x>=640 || x<0 || y>=350 || y<0) return;
  _setcolor(color);
  _floodfill(x,y,-1);
 }
}

void setfillstyle  (word_s pat,word_s col)
{
  pat=pat*8; fiA.color=col;fiA.pattern=pat;
  //_setfillmask(&fill[pat]);
}

void bar (short a,short b,short c,short d)
{short e;e=_getcolor();_setcolor(fiA.color);
_rectangle (_GFILLINTERIOR,a,b,c,d);_setcolor(e);}

void  setviewport(short a,short b,short c,short d)
{  _setviewport(a,b,c,d);
   vpA.left=a;vpA.top=b;vpA.right=c;vpA.bottom=d;}

void getlinesettings(struct linesettingstype   *li)
  {
  li->linestyle=_getlinestyle();
  li->upattern=0;
  li->thickness=lsA.thickness;}

void setlinestyle (word_s linestyle,word_s thickness)
  { tol=0;
    if( linestyle==-3) { _setlinestyle(-1);tol=3; }
    else _setlinestyle(linestyle);
    lsA.linestyle=linestyle;
    lsA.thickness=thickness;
  }

void getfillsettings (struct fillsettingstype   *fi)
 { fi->pattern=fiA.pattern;fi->color=fiA.color;}

void linet( short a,short b,short c,short d)
{ short e,f;e=c;f=d;
  if( tol!=3 ) { _moveto(a,b);_lineto(c,d);}
  if(lsA.thickness==3)
   {
    if(a==c){a--;c--;}
    else{b--;d--;}
    _moveto(a,b);_lineto(c,d);
     if(a==c){a+=2;c+=2;}
     else{b+=2;d+=2;}
    _moveto(a,b);_lineto(c,d);
   }
  _moveto(e,f);
}

void rectangle(short a,short b,short c,short d)
{  if(tol!=3) _rectangle (_GBORDER,a,b,c,d);
   if(lsA.thickness==3)
    {
    _rectangle (_GBORDER,a-1,b-1,c+1,d+1);
    _rectangle (_GBORDER,a+1,b+1,c-1,d-1);
    }
}
//***************** Универсальные функции графики ****************************

void putpix(word c, word x, word y)
{
 byte n, wc=0x80, *pc;

 pc=(byte*)(0xa0000L+y*80+(x>>3));
 n=x&7;

 outp(0x3ce,5);

 outp(0x3cf,0);  //Режим записи 0
 outp(0x3ce,8);  /* 8 - это индекс pегистpа маски битов (обpащ. по 0x3CF) */
 outp(0x3c4,2);  /* 2 - это индекс pегистpа маски каpт (обpащ. по 0x3C5) */

 wc=wc>>n;

// outp(0x3cf,01); //wc);                          /* маска битов */
// outp(0x3c5,0xF);                         /* маска каpт - все */
// *pc = 0x00;                           /* чистка */
 outp(0x3c5,c);                          /* маска каpт - цвет */
 *pc = wc;                           /* запись цвета */
 outp(0x3cf,0xff);                           /* восст.маски битов */
 outp(0x3c5,15);                             /* маска каpт - все */
}

void grab_bmp(char *tip)
{
 char *p0,*p1,*p2,*p3,*pc,mask,px,ic,buf[340];

 char name[11];
 int i,ii,tmp1,hd;
 BITMAPFILEHEADER B_head;
 BITMAPINFOHEADER BI_head;
 RGBQUAD          Palitr;

 i=0;
 do sprintf(name,"%.3s%d.bmp",tip,i++);
 while((hd=open(name,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0);

 B_head.bfType=0x4D42; B_head.bfReserved1=B_head.bfReserved2=0;
 B_head.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)+640*350;
 B_head.bfOffbits=B_head.bfSize-640*350;

 write(hd,&B_head,sizeof(BITMAPFILEHEADER));

 BI_head.biSize=sizeof(BITMAPINFOHEADER);
 BI_head.biWidth=640; BI_head.biHeight=350; BI_head.biPlanes=1;
 BI_head.biBitCount=8; BI_head.biCompression=0;
 BI_head.biSizeImage=640*350;
 BI_head.biXPelsPerMeter=BI_head.biYPelPerMeter=BI_head.biClrUsed=BI_head.biClrImportant=0;

 write(hd,&BI_head,sizeof(BITMAPINFOHEADER));
 for(i=0;i<16;i++)
 {
  if(i&0x8) tmp1=0x55;else tmp1=0x00;;
  if(i&0x4) Palitr.rgbBlue=tmp1|0xAA; else Palitr.rgbBlue=tmp1;
  if(i&0x2) Palitr.rgbGreen=tmp1|0xAA; else Palitr.rgbGreen=tmp1;
  if(i&0x1) Palitr.rgbRed=tmp1|0xAA; else Palitr.rgbRed=tmp1;
  write(hd,&Palitr,sizeof(RGBQUAD));
 }
 lseek(hd,(256-16)*sizeof(RGBQUAD),SEEK_CUR);

 for(i=0;i<350;i++) for(ii=0;ii<640;ii++){ tmp1=_getpixel(ii,349-i); write(hd,&tmp1,1);}

/* for(pc=(char *)0xA0000,i=0;i<350;i++,pc+=80)
 {
  for(ic=0;ic<4;ic++)
  {
   outpw(0x3CE,(ic<<8)|4);
   for(ii=0;ii<80;ii++) buf[ic*80+ii] = *(pc+ii);
  }

  for(ii=0;ii<80;ii++,mask=1)
   for(ic=0;ic<8;ic++,mask<<=1)
   {
     p0=buf;  p1=p0+80;  p2=p1+80;  p3=p2+80;
     px=0;
     if(*p0++ & mask) px |= 1;
     if(*p1++ & mask) px |= 2;
     if(*p2++ & mask) px |= 4;
     if(*p3++ & mask) px |= 8;
     write(hd,&px,1);
   }
 }
 close(hd);*/
}

void grab_pcx(char *tip)
{
 PCXHEADER *pp;
 byte msk,msk_o,tmp,count_b=0;
 int i,ii,iii,hd;
 byte *p_buf, name[15];

 pp=calloc(sizeof(PCXHEADER),1); i=0;
 do sprintf(name,"%.3s%d.pcx",tip,i++);
 while((hd=open(name,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0);

 pp->manuf=0x0A ; pp->hard   =0x05 ; pp->encod=0x01 ; pp->bitpx  =0x01 ;
 pp->x1   =0x00 ; pp->y1     =0x00 ; pp->x2   =0x280; pp->y2     =0x15E;
 pp->hres =0x280; pp->vres   =0x15E; pp->vmode=0x00 ; pp->nplanes=0x04 ;
 pp->bplin=0x50 ; pp->palinfo=0x01 ; pp->shres=0x280; pp->svres  =0x00 ;

 for(i=0;i<16;i++)
 {
  if(i&8) msk=0x55; else msk=0;
  if(i&4) pp->clrma[i*3]  =0xAA|msk; else pp->clrma[i*3]  =msk;
  if(i&2) pp->clrma[i*3+1]=0xAA|msk; else pp->clrma[i*3+1]=msk;
  if(i&1) pp->clrma[i*3+2]=0xAA|msk; else pp->clrma[i*3+2]=msk;
 }
 write(hd,pp,sizeof(PCXHEADER));
 for(p_buf=(byte *)0xA0000,i=pp->y1;i<pp->y2;i++,p_buf+=80)
 {
  for(ii=0;ii<pp->nplanes;ii++)
  {
   outpw(0x3CE,(ii<<8)|4);
   for(iii=0;iii<pp->bplin;iii++)
   {
    msk=p_buf[iii];
    if(msk_o==msk|| !count_b)
    {
     count_b++;
     if(count_b==0x3F) {tmp=0xFF; write(hd,&tmp,1); write(hd,&msk,1); count_b=0;}
    }
    else
    {
     if(count_b>1) {tmp=count_b|0xC0; write(hd,&tmp,1); count_b=1;}
     else if(msk_o>=0xC0) {tmp=0xC1; write(hd,&tmp,1);}
     write(hd,&msk_o,1);
    }
    msk_o=msk;
   }
  }
  schedule();
 }
 if(count_b>1) {tmp=count_b|0xC0; write(hd,&tmp,1);}
 else if(msk_o>=0xC0) {tmp=0xC1; write(hd,&tmp,1);}
 if(count_b) write(hd,&msk_o,1);

 free(pp); close(hd);
}