/*  draw_a_man.c
    written by Marco in 2010, revised in 2020
    
    This program draws the picture of a man with some characters 
    and saves the image in the file "man.xbm"

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.  */


#include<stdio.h>
#include<stdlib.h>

/* function prototypes */
void clear(char *img);
void plot(char *img, int x, int y, char c);
void iswap(int *a, int *b);
void line(char *img, int x1, int y1, int x2, int y2, char c);
void hline(char *img, int x1, int x2, int y, char c);
void vline(char *img, int x, int y1, int y2, char c);
void box(char *img, int x1, int y1, int x2, int y2, char c, char s);
void circle(char *img, int xc, int yc, int r, char c, char s);
void byte2hex(char c, char *hc, char *lc);
void save(char *img, char *filename);
void put14seg(char *img, int x, int y, char n, int s);
void write14seg(char *img, int x, int y, char *a, int s);


/* draw a man surronded by a frame with characters */
void main(){

 char g[32767];
 char imagename[13]="man.xbm";

 clear(g);

 circle(g,255,375,100,1,0);
 circle(g,215,400,10,1,1);
 circle(g,295,400,10,1,1);
 line(g,255,400,240,360,1);
 line(g,255,400,270,360,1);
 hline(g,240,270,360,1);
 hline(g,220,290,320,1);
 box(g,240,275,270,175,1,1);
 line(g,240,175,220,75,1);
 line(g,270,175,290,75,1);
 hline(g,220,200,75,1);
 hline(g,290,310,75,1);
 line(g,240,275,180,215,1);
 line(g,270,275,330,215,1);
 box(g,55,50,455,500,1,0);
 write14seg(g,120,480,"0123456789/-+*=><ABCDEFGHIJKLMNOPQRSTUVWXYZ\0",1);
 write14seg(g,90,250,"IK2PIH\0",2);
 write14seg(g,350,250,"MARCO\0",2);
 save(g,imagename);
}



/* clear the image */
void clear(char *img)
{
 int i;
 for(i=0;i<=32767;i++)
                   img[i]=0;
 return;
}



/* set/reset the point (x,y) */
void plot(char *img, int x, int y, char c)
{
 if((x>=0)&&(y>=0)&&(x<=511)&&(y<=511)&&((c==0)||(c==1)))
  {if(c==0) img[x/8+(64*(511-y))]&=~(1<<(x%8));
   else     img[x/8+(64*(511-y))]|=(1<<(x%8));}
 return;
}



/* swap the two integers a and b */
void iswap(int *a, int *b)
{
 int t;
 t=*a;
 *a=*b;
 *b=t;
 return;
}



/* draw a black/white line from x1,y1 to x2,y2 with Bresenham */
void line(char *img, int x1, int y1, int x2, int y2, char c)
{
 int x,y,adx,ady,m,e,s;

 adx=abs(x2-x1);
 ady=abs(y2-y1); 
 s=0;

 if(adx<ady)
     {iswap(&x1,&y1);
      iswap(&x2,&y2);
      iswap(&adx,&ady);
      s=1;}
 
 if(x1>x2)
     {iswap(&x1,&x2);
      iswap(&y1,&y2);}

 m=2*ady;
 e=m-adx;
 for(x=x1,y=y1;x<=x2;x++)
                   {if(s==0) plot(img,x,y,c);
                    else     plot(img,y,x,c);
                    e+=m;
                    if(e>0)
                          {if(y2>=y1) y++;
			   else       y--;
	                   e-=2*adx;}
                    } 
return;
}



/* draw a black/white horizontal line from x1,y to x2,y */
void hline(char *img, int x1, int x2, int y, char c)
{
 int x;

 if(x1>x2)
      iswap(&x1,&x2);

 for(x=x1;x<=x2;x++)
      plot(img,x,y,c);
 return;
}



/* draw a black/white vertical line from x,y1 to x,y2 */
void vline(char *img, int x, int y1, int y2, char c)
{
 int y;

 if(y1>y2)
      iswap(&y1,&y2);

 for(y=y1;y<=y2;y++)
      plot(img,x,y,c);

 return;
}




/* draw a black/white empty/filled rectangle given two opposite vertices */
void box(char *img, int x1, int y1, int x2, int y2, char c, char s)
{
 int y;

 if(s==0)
  {hline(img,x1,x2,y1,c);
   hline(img,x1,x2,y2,c);
   vline(img,x1,y1,y2,c);
   vline(img,x2,y1,y2,c);}
 else
   {if(y1>y2)
         iswap(&y1,&y2);
    for(y=y1;y<=y2;y++)
         hline(img,x1,x2,y,c);
   }
return;
}




/* draw a black/white empty/filled circle given center and radius with Bresenham */
void circle(char *img, int xc, int yc, int r, char c, char s)
{
 int x,y,d;

 d=3-r-r;
 for(x=0,y=r;x<y;x++)
   {
   if(d>0)
    {y--;
     d+=4*(x-y)+10;}
   else
     d+=4*x+6;

   if(s==0)
      {plot(img,xc+x,yc+y,c); 
       plot(img,xc-x,yc+y,c); 
       plot(img,xc+x,yc-y,c); 
       plot(img,xc-x,yc-y,c); 
       plot(img,xc+y,yc+x,c); 
       plot(img,xc-y,yc+x,c); 
       plot(img,xc+y,yc-x,c); 
       plot(img,xc-y,yc-x,c);}
   else
      {hline(img,xc-x,xc+x,yc+y,c);
       hline(img,xc-x,xc+x,yc-y,c);
       hline(img,xc-y,xc+y,yc+x,c);
       hline(img,xc-y,xc+y,yc-x,c);}
   }
 return;
}
  


/* convert a byte to it's hexadecimal equivalent */
void byte2hex(char c, char *hc, char *lc)
{
 char l,h; 

 l=(c & 0x0f);
 if(l<=9) *lc='0'+l;
 else *lc='a'+l-10;

 h=((c>>4) & 0x0f);
 if(h<=9) *hc='0'+h;
 else *hc='a'+h-10;

 return;
}



/* save the image to disk in xbm format */
void save(char *img, char *filename)
{
FILE *fp;
int i,j;
char hc,lc;

if(!(fp=fopen(filename,"w")))
   {fprintf(stderr,"Can't open the file\n");
    exit(EXIT_FAILURE);}

fprintf(fp,"#define image_width 512\n");
fprintf(fp,"#define image_height 512\n");
fprintf(fp,"static unsigned char image_bits[] = {\n");

for(j=0;j<=511;j++)
   {for(i=0;i<=63;i++)
        {byte2hex(img[i+64*j],&hc,&lc);
         if(!((j==0) && (i==0)) && (i%16==0)) fprintf(fp,"\n");
         fprintf(fp,"0x%c%c",hc,lc);
         if(!((j==511) && (i==63))) fprintf(fp,",");}
   }
 
fprintf(fp,"};\n");
fclose(fp);
return;
}



/* write chars (0123456789/-+*=><ABCDEFGHIJKLMNOPQRSTUVWXYZ) in 14 seg format at (x,y) */
/* s=scale */
/* used by the "write14seg" function */
void put14seg(char *img, int x, int y, char n, int s)
{
 /* characters belonging to each segment */
 char a[25]="02356789ABCDEFGIOPQRSTZ$$";
 char b[25]="0123489ABDHJMNOPQRUW$$$$$";
 char c[25]="01345689ABDGHJMNOQSUW$$$$";
 char d[25]="0235689BCDEGIJLOQSUZ=$$$$";
 char e[25]="0268ACEFGHJKLMNOPQRUVW$$$";
 char f[25]="045689ACEFGHKLMNOPQRSUVW$";
 char g1[25]="2456789AEFHKPRS-+*=$$$$$$";
 char g2[25]="23456789ABEGHPRS-+*=$$$$$";
 char h[25]="MNXY*>$$$$$$$$$$$$$$$$$$$";
 char i[25]="BDIT+*$$$$$$$$$$$$$$$$$$$";
 char j[25]="17KMVXYZ*/<$$$$$$$$$$$$$$";
 char k[25]="VWXZ*/>$$$$$$$$$$$$$$$$$$";
 char l[25]="7BDITY+*$$$$$$$$$$$$$$$$$";
 char m[25]="KNQRWX*<$$$$$$$$$$$$$$$$$";

 int z; /* counter */

 /* for each of the 14 segments draw the corresponding line if required */
 for(z=0;z<=24;z++)
          {if(n==a[z]) line(img,x,y+(8*s),x+(4*s),y+(8*s),1);
          if(n==b[z]) line(img,x+(4*s),y+(4*s),x+(4*s),y+(8*s),1);
          if(n==c[z]) line(img,x+(4*s),y,x+(4*s),y+(4*s),1);
          if(n==d[z]) line(img,x,y,x+(4*s),y,1);
          if(n==e[z]) line(img,x,y,x,y+(4*s),1);
          if(n==f[z]) line(img,x,y+(4*s),x,y+(8*s),1);
          if(n==g1[z]) line(img,x,y+(4*s),x+(2*s),y+(4*s),1);
          if(n==g2[z]) line(img,x+(2*s),y+(4*s),x+(4*s),y+(4*s),1);
          if(n==h[z]) line(img,x+(2*s),y+(4*s),x,y+(8*s),1);
          if(n==i[z]) line(img,x+(2*s),y+(4*s),x+(2*s),y+(8*s),1);
          if(n==j[z]) line(img,x+(2*s),y+(4*s),x+(4*s),y+(8*s),1);
          if(n==k[z]) line(img,x+(2*s),y+(4*s),x,y,1);
          if(n==l[z]) line(img,x+(2*s),y+(4*s),x+(2*s),y,1);
          if(n==m[z]) line(img,x+(2*s),y+(4*s),x+(4*s),y,1);}
 return;
}



/* write string "a" in 14 segment format at (x,y) with scale factor "s" */
void write14seg(char *img, int x, int y, char *a, int s)
{
 int i;

 i=0;
 while(a[i]!='\0')
      {put14seg(img,x+(i*6*s),y,a[i],s);
       i++;}
 return;
}
