/* Brushprint.c 
  Autor: Thomas Kern
         Auwaldstr. 95
         7800 Freiburg i. Brsg.*/

#define spaltmaxdr 2980 /* Hier bei Druckeranpassung ändern */
#define maxzahlfile 80  /* 8 Bit * 80 Byte = 640 max hor Aufl. (Brush) */
#define maxzahldr 640

#include <stdio.h>
#include <exec/types.h>
#include <fcntl.h> /* für unbuffered I/O ca 10 % schneller */

FILE *bfile,*drfile;
UBYTE fdaten[maxzahlfile][24],druck1[maxzahldr][3],druck2[spaltmaxdr][3];
UBYTE druck3[spaltmaxdr][3];
int breite,hoehe,hvergr=1,brvergr=1,byteproz,zeilenz=1,drbreite;
int zcountur=0,zcountbild=0,vzaehler=1,drdesc;
UBYTE nplanes,masking,potur=128,potbild= 128;

LONG getl(file) /* holt longword von file */
 FILE *file;
{
 return getw(file) * 65536L + getw(file);
} 

BOOL checkilbm(file) /* ILBM - File ? */
 FILE *file;
{
 BOOL hilf = TRUE;
 if (getc(file) != (char)73) hilf = FALSE; /* I */
 if (getc(file) != (char)76) hilf = FALSE; /* L */
 if (getc(file) != (char)66) hilf = FALSE; /* B */
 if (getc(file) != (char)77) hilf = FALSE; /* M */
 return hilf;
}

BOOL findebody(file) /* sucht nach BODY-Chunk */
 FILE *file;
{
 char c;
 BOOL hilf=FALSE;
 c = getc(file);
 while ((! hilf) && !feof(file)) {
       if (c == (char)0x42) {                                     /* B */
          if ((c = getc(file)) == (char)0x4f)                     /* O */
             if ((c = getc(file)) == (char)0x44)                  /* D */
                if ((c = getc(file)) == (char)0x59) hilf = TRUE;  /* Y */
          }
          else c = getc(file);
       }
 return hilf;
}

UBYTE hi(i) /* höherwertiges Byte */ 
 int i;
{
 return (UBYTE)(i/256);
}

UBYTE lo(i) /* niederwertiges Byte */
 int i;
{
 return (UBYTE)(i % 256);
}

void grein(br)  /* schaltet Grafikmodus ein */
 int br;
{
 UBYTE hi(),lo(),grafikein[6];
 grafikein[0]=13; /* erstmal ein CR */
 grafikein[1]=27; grafikein[2]=42; grafikein[3]=40; /* ESC "*" 40 n1 n2 */
 grafikein[4]=lo(br);grafikein[5]=hi(br);           /* Bei Anpassung ändern */
 write(drdesc,grafikein,6);                         /* CR + Grafikmodus ein */
}

void linef()
{
 UBYTE linefeed[4];
 linefeed[0]=28;linefeed[1]=51;linefeed[2]=48;linefeed[3]=10;
 write(drdesc,linefeed,4);  /* linefeed auf 48 / 360 inch + LF */
}

void drucke1(br) /* schickt druck1[][] an Drucker */
int br;
{
 grein(br);
 write(drdesc,druck1,3*br); /* Das komplette Array als String schicken */
 linef();
}

void drucke2(br) /* Dasselbe mit druck2[][] */
int br;
{
 grein(br);
 write(drdesc,druck2,3*br); /* Das komplette Array als String schicken */
 linef();
}

void drucke3(br) /* s.o. zusätzlich noch druck3[][] löschen */
int br;
{
 int i,j;
 grein(br);
 write(drdesc,druck3,3*br); /* Das komplette Array als String schicken */
 linef();
 for (i=0;i<br;i++)
     for (j=0;j<=2;j++) druck3[i][j]=0; 
}

void andrucker() /* ggf Vergrößern und an Drucker schicken */
{
 void drucke1(),drucke2(),drucke3();
 register int i,j,l,m; /* Das Vergrößern ist am zeitkritischsten */
 if ((hvergr ==1)&&(brvergr==1)) {
     drucke1(breite);
     return;
     }
 drbreite=breite*brvergr;
 for (j=0;j<=2;j++) { /* Breitenvergrößerung */
     m=0;
     for (l=0;l<breite;l++)
         for (i=1;i<=brvergr;i++) {
         druck2[m][j]=druck1[l][j];
         m++;
         }
     }
 if (hvergr == 1) {
    drucke2(drbreite);
    return;
    }
 zcountur=0; /* Höhenvergr. zcountur = Pos in druck2[][] */
 potur =  128; /* = 2^7 für bitweises Vergleichen */
 do {
    if (vzaehler <= hvergr) {
       l=zcountur / 8;
       m=zcountbild / 8; /* zcountbild = Pos in druck3[][] */
       for (i=0;i<drbreite;i++)
           if ((druck2[i][l]/potur)&1) druck3[i][m] |= potbild;
       vzaehler++;
       zcountbild++;
       potbild >>= 1;
       if (potbild == 0) potbild = 128;
       if (zcountbild > 23) { /* eine komplette Zeile an Drucker schicken */
          drucke3(drbreite);
          zcountbild = 0;
          potbild = 128;
          }
       }
     else {
       vzaehler=1;
       zcountur++;
       potur >>= 1;
       if (potur == 0) potur = 128;
       }
    }
  while (zcountur <= 23); /* wenn druck2[][] komplett vergr., dann weiter */
}

void holezeile(i,oder) /* dekomprimiert Zeile nach one-byte Verfahren */
int i;                 /* (oder so ähnlich) */
BOOL oder; /* bei TRUE werden die Daten dazugeORt */
{
 UBYTE k;
 BYTE bef;
 int j,spzaehl=0;
 while (spzaehl <= byteproz) {
    bef=getc(bfile);
    if ((bef>=0)&&(bef<=127)) /* keine Kompression für die nächsten bef Byte */
       for (j=0;j<=bef;j++) {
           fdaten[spzaehl][i]= (oder) ? fdaten[spzaehl][i] | getc(bfile):getc(bfile);
           spzaehl++;
           }
       else { /* die nächsten (-bef+1) Byte sind gleich */
       bef = -bef +1;
       k=getc(bfile); /* und zwar = k */
       for (j=1;j<=bef;j++) {
           fdaten[spzaehl][i] = (oder) ? fdaten[spzaehl][i] | k : k;
           spzaehl++;
           }
       }
    }
}

void compressed() /* komprimiertes file zeilenweise lesen */
{
 int i,j,brz,zez=0;
 void holezeile();
 while ((zez<=23)&&(zeilenz<=hoehe)&& !feof(bfile)) {
       holezeile(zez,(BOOL)FALSE); /* erste bitplane normal */
       for (i=2;i<=nplanes;i++) holezeile(zez,(BOOL)TRUE); /* die übrigen dazuORen */
       zez++;
       zeilenz++;
       }
 for (i=zez;i<=23;i++) /* evtl Rest mit 0 auffüllen */
     for (j=0;j<=byteproz;j++) fdaten[j][i]=0;
}


void nichtcompressed() /* nichtkomprimiertes file lesen */
{
 int i=0,j,l;
 while ((i <= 23)&&(zeilenz<=hoehe)&& !feof(bfile)) {
   for (j=0;j<=byteproz;j++) fdaten[j][i] = getc(bfile);
   for (l=2;l<=nplanes;l++)
       for (j=0;j<=nplanes;j++) fdaten[j][i] |= getc(bfile);
   i++;
   zeilenz++;	
   }
 for (l=i;l<=23;l++) /* s.o. */
     for (j=0;j<=byteproz;j++) fdaten[j][l]=  0;
}

void konvertiere() /* Daten druckergerecht aufbereiten */
{
 UBYTE a,b,hilf;
 int fsp,fz,brz,drspalte=0;
 int drzeile=0;
 for (drzeile=0;drzeile<=2;drzeile++) { /* 24 Brushzeilen ergeben bitweise */
     b= 128;                            /* 3 * 8 Druckerbytes (eine Spalte)*/
     fsp=0;
     for (brz=0;brz<breite;brz++) {
         hilf=0;
         a= 128;
         for (fz=drzeile*8;fz<= 7+drzeile*8;fz++) {
             if ((fdaten[fsp][fz]/b)&1) hilf += a;
             a >>= 1;
             }
         druck1[brz][drzeile]=hilf;
         if (b>1) b >>= 1;
            else {
                 b= 128;
                 fsp++;
                 }
         }
     }
}

main(argc,argv)
 int argc;
 char *argv[];
{
 int i,j;
 char *gets(), buffer[20];
 void nichtcompressed(),compressed(),konvertiere(),andrucker();
 BOOL compress,findebody(),checkilbm();
 ULONG hilfl,flaenge,bodylaenge,getlong();
 FILE  *fopen();
 if (argc == 1) {
    printf("USAGE: BrushPrint <filename> [ BV [ HV ]]\n");
    printf("written by Thomas Kern\n");
    exit();
    }
 bfile=fopen(argv[1],"r"); /* Eingabe durch buffered I/O */
 if (bfile == NULL) {
    printf("File %s not found\n",argv[1]);
    exit(2);
    }
 hilfl = getl(bfile); /* 4 bytes überlesen */
 flaenge = 8L + getl(bfile) ;
 if (!checkilbm(bfile)) {
    printf("Kein ILBM-File!\n");
    exit(3);
    }
 hilfl = getl(bfile);
 hilfl = getl(bfile);
 breite = getw(bfile);
 if (breite > maxzahldr) { 
    printf("Brush ist zu breit");
    exit(0);
    }
 hoehe = getw(bfile);
 hilfl = getl(bfile);
 nplanes = getc(bfile);
 masking = getc(bfile);
 compress = getc(bfile);
 printf("Filelänge: %ld Höhe: %d Breite: %d \n",flaenge,hoehe,breite);
 printf("Bitplanes: %d Komprimiert: %d ",nplanes,compress);
 printf("Maskenbyte: %d\n",masking);
 if (argc >= 2) {
    brvergr = atoi(argv[2]);
    if (brvergr <=0) brvergr =1;
    }
 if (argc >=3) {
    hvergr = atoi(argv[3]);
    if (hvergr <=0) hvergr =1;
    }
 printf("Breitenvergr: %d Höhenvergr: %d\n",brvergr,hvergr);
 if (brvergr*breite > spaltmaxdr) {
    printf("Breite * Vergr.= %d. Das ist zu breit.\n",brvergr*breite);
    exit(4);
    }
 if (!findebody(bfile)) {
    printf("BODY-Chunk nicht gefunden\n");
    exit(5);
    }
 bodylaenge = getl(bfile);
 drdesc = open("PAR:",O_WRONLY); /* Ausgabe durch unbuffered I/O */
 if (drdesc == -1) {
    printf("Can't open PAR:\n"); /* nicht PRT: verwenden, sonst gibt's */
    exit(6);                     /* Datensalat beim Drucker ! */
    }
 byteproz = (((breite-1)/16)+1)*2-1; /* Anzahl der Bytes pro Zeile ist immer */
 zeilenz =1;                         /* gerade (also nicht breite/8) */
 if (masking == 1) nplanes++; /* Maske ist zusätzliche Plane, kommt selten vor */
 while (zeilenz <= hoehe) {
       if (compress) compressed();
          else nichtcompressed();
       konvertiere();
       andrucker();
       }
 close(drdesc);
}
