/* Copyright (C) 1996-2000 Justin Frankel
** Bitmap compiler.
*/
#include <stdio.h>
#define USE_DJGPP

unsigned char *BallData;
long int VirtualEDI;

void FlushEDI() {
  if (VirtualEDI > 127) {
#ifdef USE_DJGPP
    printf("\taddl $%ld, %%%%edi\n",VirtualEDI);
#else
    printf("\tadd edi, %ld\n",VirtualEDI);
#endif
    VirtualEDI = 0;
  }
}

void AddEDI(int amount) {
  VirtualEDI += amount;
}

void WriteLong(char *x) {
  long int *z;
  z = (long int *) x;
  FlushEDI();
#ifndef USE_DJGPP
  if (VirtualEDI) printf("\tmov dword ptr [edi+%ld], %ld\n",VirtualEDI,*z);
  else printf("\tmov dword ptr [edi], %ld\n",*z);
#else
  if (VirtualEDI) printf("\tmovl $%ld, %ld(%%%%edi)\n",*z, VirtualEDI);
  else printf("\tmovl $%ld, (%%%%edi)\n",*z);
#endif
  AddEDI(4);
}

void WriteShort(char *x) {
  short int *z;
  z = (short int *) x;
  FlushEDI();
#ifndef USE_DJGPP
  if (VirtualEDI) printf("\tmov word ptr [edi+%ld], %ld\n",VirtualEDI,*z);
  else printf("\tmov word ptr [edi], %ld\n",*z);
#else
  if (VirtualEDI) printf("\tmovw $%ld, %ld(%%%%edi)\n",*z, VirtualEDI);
  else printf("\tmovw $%ld, (%%%%edi)\n",*z);
#endif
  AddEDI(2);
}

void WriteChar(char *x) {
  FlushEDI();
#ifndef USE_DJGPP
  if (VirtualEDI) printf("\tmov byte ptr [edi+%ld], %d\n",
     VirtualEDI,*x & 0x00ff);
  else printf("\tmov byte ptr [edi], %d\n",*x & 0x00ff);
#else
  if (VirtualEDI) printf("\tmovb $%ld, %ld(%%%%edi)\n",*x & 0x00ff, VirtualEDI);
  else printf("\tmovb $%ld, (%%%%edi)\n",*x & 0x00ff);
#endif
  AddEDI(1);
}

void Compile(unsigned char *Data, int width, int height, 
             unsigned char TransChar, char *FuncName, int scrwidth) {
  int linecount, x, runlength;
  unsigned char *TmpData;
  height++;
#ifndef USE_DJGPP
  printf("; Generated with the Nullsoft Compiler. Call this routine \n"
         "; with edi set to the location in memory you would like to \n"
         "; blit to. Dimensions for the image are %d by %d (8 bpp), \n"
         "; the transparent color is %d and the target screen width is %d\n\n",
           width, height, TransChar, scrwidth);
 
  printf(".386p\n"
         ".model flat, C\n"
         ".code\n"
         "\tpublic %s\n"
         "%s proc C\n", FuncName, FuncName);
#else
  printf("/* \n   Generated with the Nullsoft Compiler. Call this routine \n"
         "   with the location in memory you would like to \n"
         "   blit to. Dimensions for the image are %d by %d (8 bpp), \n"
         "   the transparent color is %d and the target screen width is %d\n"
         "*/\n\n",
             width, height, TransChar, scrwidth);
 
  printf("void %s(void *output) {\n"
         "  asm(\"\n", FuncName);

#endif
  linecount = 0;
  for ( x = 0; x < (width*height); x ++) {
    for (runlength = 0, TmpData = Data; *TmpData == TransChar; 
         TmpData++, runlength++);
    if (runlength + linecount > width) runlength = width - linecount;
    if (runlength) { 
      AddEDI(runlength);
      x += runlength;
      Data += runlength;
      linecount += runlength;
    }
    else {
      for (runlength = 0, TmpData = Data; *TmpData != TransChar; 
           TmpData++, runlength++);
      if (linecount + runlength > width) runlength = width - linecount;
      while (runlength > 3) {
        runlength -= 4;
        WriteLong(Data);
        Data += 4;
        linecount += 4;
        x+=4;
      }
      if (runlength > 1) {
        runlength -= 2;
        WriteShort(Data);
        Data += 2;
        linecount += 2;
        x+=2;
      }
      if (runlength > 0) {
        runlength--;
        WriteChar(Data);
        Data ++;
        linecount ++;
        x++;
      }
    }
    if (linecount >= width) {
      AddEDI(scrwidth-width);
      linecount = 0;
    }
  }
#ifndef USE_DJGPP
  printf("\tret\n");
  printf("%s ENDP\n", FuncName);
  printf("END\n");
#else
  printf("  \"\n");
  printf("  ::\"D\" (output)\n  : \"%%edi\");\n");
  printf("}\n");
#endif
}

void main(int argc, char *argv[]) {
  int x,y;
  FILE *fp;
  int width, height, transnum, screenwidth;
  fprintf(stderr,"Nullsoft image compiler v0.9\n");
#ifndef USE_DJGPP
  fprintf(stderr,"For: Turbo Assembler + flat mode\n");
#else
  fprintf(stderr,"For: djgpp v2\n");
#endif
  if (argc != 7) {
#ifndef USE_DJGPP
    fprintf(stderr,"Usage:\n"
       "   Compile File.raw width height transnum screenwidth \"Function Name\" > File.asm\n");
#else
    fprintf(stderr,"Usage:\n"
       "   Compile File.raw width height transnum screenwidth \"Function Name\" > File.h\n");
#endif
    exit(1);
  }
  sscanf(argv[2],"%d",&width);
  sscanf(argv[3],"%d",&height);
  sscanf(argv[4],"%d",&transnum);
  sscanf(argv[5],"%d",&screenwidth);
  fp = fopen(argv[1],"rb");
  if (fp == NULL) {
    fprintf(stderr,"Sorry, File not found\n");
    exit(1);
  }
  fseek(fp,0,SEEK_END);
  BallData = (char *) malloc(ftell(fp) + 100);
  if (!BallData) {
    fprintf(stderr,"Sorry, Insufficient Memory");
    exit(1);
  }
  if (ftell(fp) != width*height) {
    fprintf(stderr,"Sorry, File does not seem to be the correct size\n");
    exit(1);
  }
  fseek(fp,0,SEEK_SET);
  
  for (y = 0; y < height; y ++) {
    fread(BallData + (((height-1) - y) * width),width,1,fp);
  } 
  fclose(fp);
  fprintf(stderr,"COMPILING...\n");
  Compile(BallData,width,height,transnum & 0x00ff, argv[6], screenwidth );
  fprintf(stderr,"DONE\n");
  free(BallData);
}

