/*=========================================================================
 *           Envision: Font editor for Atari                              *
 ==========================================================================
 * File: map.c                                                            *
 * Author: Mark Schmelzenbach                                             *
 * Started: 07/30/97                                                      *
 =========================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
  
#include <grx20.h>

#ifdef __linux__
#include <vga.h>
#else
#include <dos.h>
#endif

#include "envision.h"

int do_mode(int m);
int draw_screen(int b);
int draw_map();

int sx, sy, scx, scy, cx, cy, dc;
int cw,ch,tm;
int mode, hidden, ratio;
int base;
unsigned char curs, *map;
GrContext *back, *chars;

/*=========================================================================*/
int map_panel()
{
 if (hidden) return 0;
 GrSetContext(upd);
 GrClearContext(0);
 drawbutton(0,0,"Resi*Ze"); cmds[1]='z';
 drawbutton(0,10,"*Mode"); cmds[2]='m';
 drawbutton(0,20,"*Ratio"); cmds[3]='r';
 drawbutton(0,30,"*Find"); cmds[4]='f';
 drawbutton(0,40,"*Draw ch"); cmds[5]='d';
 drawbutton(0,50,"*Save"); cmds[6]='s';
 drawbutton(0,60,"*Load"); cmds[7]='l';
 drawbutton(0,70,"*Clear"); cmds[8]='c';
 drawbutton(0,80,"*Hide"); cmds[9]='h';
 cmds[0]=113;
 GrSetContext(NULL);
 GrFilledBox(248,24,319,200,0);
 GrBitBlt(NULL,251,24,upd,0,0,64,89,GrWRITE);
}
/*=========================================================================*/
int curs_pos()
{
 char buf[12];
 
 GrSetContext(dialog);
 sprintf(buf,"X:%0.3d Y:%0.3d",scx+cx,scy+cy);
/* GrFilledBox(236,6,316,13,144);
 string(228,6,buf); */
 GrFilledBox(0,0,87,7,144);
 string(0,0,buf); 
 GrSetContext(NULL);
 GrBitBlt(NULL,228,6,dialog,0,0,87,7,GrWRITE);
}
/*=========================================================================*/
int move(int dx, int dy) 
{
 int ox,oy;
 
 ox=cx; oy=cy;
 cx+=dx;
 cy+=dy;
 
 if (cx<0) {
   cx=0;
   if (scx) scx=scx-1;
     else return 0;
 } else if (cx*cw>=320) {
   cx-=1;
   if (cx+scx+1<sx) scx+=1; 
     else return 0;
 }
 if (cy<0) {
   cy=0;
   if (scy) scy=scy-1;
     else return 0;
 } else if (cy*ch+24>=200) {
   cy-=1;
   if (cy+scy>=sy-1) return 0;
    else scy+=1;
 }
 curs_pos();
 if ((ox==cx)&&(oy==cy)) draw_screen(1);
  else {
   if ((!hidden)&&(cw>8)&&(ox*16==240))
     GrFilledBox(ox*cw,24+oy*ch,ox*cw+8-1,24+oy*ch+ch-1,255|GrXOR);
   else if ((ox*cw<248)||(hidden))
     GrFilledBox(ox*cw,24+oy*ch,ox*cw+cw-1,24+oy*ch+ch-1,255|GrXOR);
   if ((!hidden)&&(cw>8)&&(cx*16==240))
     GrFilledBox(cx*cw,24+cy*ch,cx*cw+8-1,24+cy*ch+ch-1,255|GrXOR);
   else if ((cx*cw<248)||(hidden))
     GrFilledBox(cx*cw,24+cy*ch,cx*cw+cw-1,24+cy*ch+ch-1,255|GrXOR);
  }
 if (tm) {
   GrFilledBox(308,15,316,22,144);
  map_plotchr(308,15,*(map+(cx+scx)+(cy+scy)*sx),1,dfont);
 }
 return 1;
}
/*=========================================================================*/
int map_command(int cmd, int stat)
{
 int i,j,r,f;
 char buf[8], *fname;
 unsigned char *look;
 GrMouseEvent evt;

 if (tm) {
  if ((cmd!=587)&&(cmd!=589)&&(cmd!=584)&&(cmd!=592)&&(cmd!=27)) {
    i=stoa(cmd);
    *(map+(cx+scx)+(cy+scy)*sx)=i;
    cmd=0;
    GrBitBlt(NULL,cx*cw,24+cy*ch,chars,i*cw,0,i*cw+cw-1,ch-1,GrWRITE);
    GrFilledBox(cx*cw,24+cy*ch,cx*cw+cw-1,24+cy*ch+ch-1,255|GrXOR);    
    move(1,0);
  } 
 }
 
 switch (cmd) {
  case 'h': {
    if (hidden) {
     hidden=0;
     map_panel();
    } else hidden=1;
    break;
  }
  case 'f': {                                   
    f=select_draw("Select character to replace:");
    j=sx*sy;
    look=map;
    for(i=0;i<j;i++) {
     if (*look==f) {
       r=(int)(100.0*rand()/(RAND_MAX+1.0));
       if (r<ratio) *look=dc;
     }
     look++;
    }
    draw_map();
    break;
  }
  case 'c': {
    if (ratio==100) {
      memset(map,dc,sx*sy);
    } else {
      j=sx*sy;
      look=map;
      for(i=0;i<j;i++) {
        r=(int)(100.0*rand()/(RAND_MAX+1.0));
        if (r<ratio) *look=dc;
        look++;
      }
    }
    break;
  }
  case 'r': {
    ratio=get_number("Enter ratio:",ratio,100);
    return 0;
  }
  case 'd': {
    dc=select_draw("Select or type new draw char:");
    GrFilledBox(308,15,316,22,144);
    map_plotchr(308,15,dc,1,dfont);
    if (!hidden) map_panel();
    break;
  }
  case 'm': {
    do {
     i=get_number("Enter ANTIC mode:",mode,-1);
    } while ((i>=0)&&((i<2)||(i>7)));
    if (mode==i) return 0;
    if (i>0) {
      if ((i<6)&&(sx<40)) {
        error_dialog("Resize width >39");
        break;
      }
      if ((sy<24)&&(i!=7)&&(i!=5)) {
        error_dialog("Resize height >23");
        break;
      }
      cx=cy=scx=scy=0;
      mode=i;
      draw_map();
      do_mode(mode);
    }
    break;
  }
  case 'z': {
    do_size();
    GrFilledBox(80,15,135,22,144);
    sprintf(buf,"%0.3dx%0.3d",sx,sy);
    string(80,15,buf);
    curs_pos();
    break;        
  } 
  case 'u': {
    if (base) base=0;
      else base=64*8;
    do_mode(mode);
    break;
  }
  case 'e': {
    return 1;
  }
  #ifdef __linux__
  case 27: {
    buf[0]=27;
    buf[1]=buf[2]=0;
    GrMouseGetEvent(GR_M_EVENT, &evt);
    if ((evt.key==27)||(!evt.key)) {
      if (!tm) 
        bye();
      else {
        tm=0;
        GrFilledBox(228,15,315,22,144);
        string(228,15,"Draw Char-");
            map_plotchr(308,15,dc,1,dfont);
            return 0;
      }
    } else buf[1]=evt.key;
    GrMouseGetEvent(GR_M_EVENT, &evt);
    if (evt.key) buf[2]=evt.key;
    
    if (buf[1]==91) {
      if (buf[2]==68) move(-1,0);
      else if (buf[2]==67) move(1,0);
      else if (buf[2]==65) move(0,-1);
      else if (buf[2]==66) move(0,1);
      return 0;
    } 
    return 0;
  }
  #else
  case 27: {
    if (!tm) 
      bye();
    else {
      tm=0;
      GrFilledBox(228,15,315,22,144);
      string(228,15,"Draw Char-");
      map_plotchr(308,15,dc,1,dfont);
      return 0;
    }
    break;
  }
  #endif
  
  case 587: {
    move(-1,0);
    return 0;
    break;
  }
  case 589: {
    move(1,0);
    return 0;
    break;
  }
  case 584: {
    move(0,-1);
    return 0;
    break;
  }
  case 592: {
    move(0,1);
    return 0;
    break;
  }
  case 's': {
    fname=get_filename("Save map:",options.disk_image);
    if (fname) {
      if (options.disk_image)
    i=write_xfd_map(options.disk_image,fname,font,map,0);
      else 
    i=write_map(fname,font,map,0);
      free(fname);
    }
    return 0;
    break;
  }
  case 'w': {
    fname=get_filename("Save raw map:",options.disk_image);
    if (fname) {
      if (options.disk_image)
    i=write_xfd_map(options.disk_image,fname,font,map,1);
      else 
    i=write_map(fname,font,map,1);
      free(fname);
    }
    return 0;
    break;
  }
  case 'l': {
    fname=get_filename("Load map:",options.disk_image);
    if (fname) { 
      if (options.disk_image)
    look=read_xfd_map(options.disk_image,fname,font,map);
      else 
    look=read_map(fname,font,map);
      free(fname);
      if (look) map=look;
       else return 0;
      draw_map(); 
      do_mode(mode);
    }
    break;
  }
  case 't': { 
    tm=1; 
    GrFilledBox(228,15,315,22,144);
    string(228,15,"Type Mode");
    hidden=1;
    break;
  }
  default: {
    return 0;
  }
 }
 draw_screen(1);
 return 0;
}
/*=========================================================================*/
int map_click(int x, int y, int b)
{
 GrMouseEvent evt;
 int i,ox,oy;
 
 if (b&GR_M_LEFT_DOWN) b=1; else b=0;

 if ((!hidden)&&(x>=251)&&(x<=315)&&(y>=24)&&(y<=cmds[0])) {
   i=(y-14)/10;
   do {
     GrMouseGetEvent(GR_M_EVENT, &evt);
   } while(!(evt.flags&GR_M_BUTTON_UP));  
   if (cmds[i]) return(map_command(cmds[i],0));
   return 0;
 }
 if (y>=24) {
  oy=i=(y-24)/ch;
  ox=x=x/cw;
  if (b) {
    *(map+(x+scx)+(i+scy)*sx)=dc;
    x=x*cw;
    y=24+i*ch;
    GrBitBlt(NULL,x,y,chars,dc*cw,0,dc*cw+cw-1,ch-1,GrWRITE);
  }
  move(ox-cx,oy-cy);
 }
 return 0;
}
/*=========================================================================*/
int draw_screen(int b)
{
 int i;
 int x,y,ofs,lx,ly;
 unsigned char *look;
 
 look=map+scy*sx+scx;
 ofs=sx-320/cw; 
 lx=cx*cw;
 ly=cy*ch;
 y=0;
 while (y<192) {
  x=0;
  while (x<320) {
    i=*look++;
    if ((ly==y)&&(lx==x)) {
      GrSetContext(back);
      GrFilledBox(x,y,x+cw-1,y+ch-1,255);
      GrSetContext(NULL);
      GrBitBlt(back,x,y,chars,i*cw,0,i*cw+cw-1,ch-1,GrXOR);
    } else GrBitBlt(back,x,y,chars,i*cw,0,i*cw+cw-1,ch-1,GrWRITE);
    x+=cw;
  } 
  look=look+ofs;
  y+=ch;
 }
 if (!hidden)
   GrBitBlt(NULL,0,24,back,0,0,247,175,GrWRITE); 
 else 
   GrBitBlt(NULL,0,24,back,0,0,319,175,GrWRITE);
}
/*=========================================================================*/
int map_plotchr(int sx, int sy, int chr, int typ, unsigned char *fnt)
{
  unsigned char *dat,c,l,clr;
  int x,y;
  
  if ((typ==6)||(typ==7)) {
    dat=fnt+(chr&63)*8+base;
    clr=(chr>>6)+1;
  } else dat=fnt+(chr&127)*8;
  
  switch (typ) {
     case 1: { /* Gr. 0, no background */
    for(y=0;y<8;y++) {
     c=*(dat+y);
     if (chr>=128) c=255-c;
     for(x=0;x<8;x++) {
      if (c&128) GrPlot(sx+x,sy+y,10);
      c=c<<1;
     }
    }
    break;
   }
   case 2: { /* Gr. 0 */
    clr=(clut[3]&240)+(clut[2]&15);
    for(y=0;y<8;y++) {
     c=*(dat+y);
     if (chr>=128) c=255-c;
     for(x=0;x<8;x++) {
      if (c&128) GrPlot(sx+x,sy+y,clr);
        else GrPlot(sx+x,sy+y,clut[3]);
      c=c<<1;
     }
    }
    break;
   }
   case 3: { /* decenders */
    clr=(clut[3]&240)+(clut[2]&15);
    if ((chr&0x60)==0x60) l=1;
      else l=0;
    for(y=0;y<10;y++) {
     if (l) {
       if (y<2) c=0;
       else if ((y>=2)&&(y<=7))
        c=*(dat+y);
       else c=*(dat-8+y);
     } else {
       if (y<8) c=*(dat+y); else c=0;
     }
     if (chr>=128) c=255-c;
     for(x=0;x<8;x++) {
      if (c&128) GrPlot(sx+x,sy+y,clr);
        else GrPlot(sx+x,sy+y,clut[3]);
      c=c<<1;
     }
    }
    break;
   }
   case 4: { 
     for(y=0;y<8;y++) {
       c=*(dat+y);
       for(x=0;x<4;x++) {
     l=(c&192)>>6;
     if ((chr>=128)&&(l==3)) l=4;
     if (l) { 
       GrPlot(sx+x*2,sy+y,clut[l]);
       GrPlot(sx+(x*2+1),sy+y,clut[l]);
     }
     c=c<<2;
       }
     }
     break;
   }
   case 5: { 
     for(y=0;y<8;y++) {
       c=*(dat+y);
       for(x=0;x<4;x++) {
     l=(c&192)>>6;
     if ((chr>=128)&&(l==3)) l=4;
     if (l) { 
       GrPlot(sx+x*2,sy+y*2,clut[l]);
       GrPlot(sx+(x*2+1),sy+y*2,clut[l]);
       GrPlot(sx+x*2,sy+y*2+1,clut[l]);
       GrPlot(sx+(x*2+1),sy+y*2+1,clut[l]);    
     }
     c=c<<2;
       }
     }
     break;
   }
   case 6: { /* Gr. 1 */
    for(y=0;y<8;y++) {
     c=*(dat+y);
     for(x=0;x<8;x++) {
      if (c&128) { 
        GrPlot(sx+x*2,sy+y,clut[clr]);
        GrPlot(sx+(x*2+1),sy+y,clut[clr]);
      }
      c=c<<1;
     }
    }
    break;
   }
  case 7: { /* Gr. 2 */
    for(y=0;y<8;y++) {
     c=*(dat+y);
     for(x=0;x<8;x++) {
      if (c&128) { 
        GrPlot(sx+x*2,sy+y*2,clut[clr]);
        GrPlot(sx+(x*2+1),sy+y*2,clut[clr]);
        GrPlot(sx+x*2,sy+y*2+1,clut[clr]);
        GrPlot(sx+(x*2+1),sy+y*2+1,clut[clr]);
      }
      c=c<<1;
     }
    }
    break;
   }  
  default: {
    txterr("Unknown ANTIC mode requested.\n");
  }
 }
}
/*=========================================================================*/
int do_mode(int m)
{
  int w,x,i;
  
  if (chars)
    GrDestroyContext(chars);
  chars=NULL;
  
  if ((m==2)||(m==4)) {
    chars=GrCreateContext(2048,8,NULL,NULL);
    ch=cw=w=8;
  } else if (m==3) {
    chars=GrCreateContext(2048,10,NULL,NULL);
    cw=w=8;
    ch=10;
  } else if (m==5) {
    chars=GrCreateContext(2048,16,NULL,NULL);
    cw=w=8;
    ch=16;
  } else if (m==6) {
    chars=GrCreateContext(4096,8,NULL,NULL);
    cw=w=16; ch=8;
  } else if (m==7) {
    chars=GrCreateContext(4096,16,NULL,NULL);
    ch=cw=w=16;
  }
  GrSetContext(chars);
  GrClearContext(clut[0]);
  x=0;
  for (i=0;i<256;i++) {
    map_plotchr(x,0,i,m,font);
    x+=w;
  }  
  GrSetContext(NULL);
}
/*=========================================================================*/
int draw_map()
{
 char buf[40];
 
 GrFilledBox(0,6,319,22,144);
 GrHLine(0,320,14,0);
 string(8,6,"Map Editor - ");
 sprintf(buf,"Mode %0.2d [%0.3dx%0.3d]",mode,sx,sy);
 string(8,15,buf);
 string(228,15,"Draw Char-");
 map_plotchr(308,15,dc,1,dfont);
 curs_pos();
 map_panel();
}
/*=========================================================================*/
int do_map()
{
 GrMouseEvent evt;
 int i,done=0;
 
 GrClearContext(0); 
 draw_map();
 do_mode(mode);
 draw_screen(1);
 tm=0;
 do {
  GrMouseGetEvent(GR_M_EVENT, &evt);
  if (evt.flags&GR_M_BUTTON_DOWN) 
    done=map_click(evt.x,evt.y,evt.flags);
  if (evt.flags&GR_M_KEYPRESS) 
    done=map_command(evt.key,evt.kbstat);
 } while (!done);
}
