/* ------------------------------------------------------------------------ */

/* A2FCBMP.C (C) Copyright Bill Buckels 2012                                */

/* All Rights Reserved.                                                     */

/*                                                                          */

/* Licence Agreement                                                        */

/* -----------------                                                        */

/*                                                                          */

/* You have a royalty-free right to use, modify, reproduce and              */

/* distribute this source code in any way you find useful,                  */

/* provided that you agree that Bill Buckels has no warranty obligations    */

/* or liability resulting from said distribution in any way whatsoever.     */

/* If you don't agree, remove this source code from your computer now.      */

/*                                                                          */

/* Written by   : Bill Buckels                                              */

/* Email:         bbuckels@escape.ca                                        */

/*                                                                          */

/* Purpose      : This utility will allow you to convert from               */

/*                Apple II Double Hi-Res 140 x 192 x 16 color images to     */

/*                RGB 280 x 192 x 24 Bit Windows .BMP Files                 */

/*                                                                          */

/* Revision     : 1.0 First Release                                         */

/* ------------------------------------------------------------------------ */

/* Written in Large Model 16 bit Microsoft C (MSC) Version 8.00c            */

/* Note: Run in an MS-DOS emulator like DOSBox if you can't run it raw.     */

/* ------------------------------------------------------------------------ */

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

/* ------------------------------------------------------------------------ */

/* Declarations, Vars. etc.                                                 */

/* ------------------------------------------------------------------------ */

 

typedef unsigned char     uchar;

typedef unsigned int      uint;

typedef unsigned long     ulong;

 

#define ASCIIZ 0

 

 

uchar *szTextTitle =

    "A2FCBMP(C) Version 2.0 Copyright Bill Buckels 2012\n"

    "All Rights Reserved.";

 

#define SUCCESS  0

#define VALID    SUCCESS

#define FAILURE  -1

#define INVALID  FAILURE

 

#define NUM_RGB_COLORS     3

 

 

enum {  BLACK = 0,

        BLUE,

        GREEN,

        CYAN,

        RED,

        MAGENTA,

        BROWN,

        WHITE,

        GRAY,

        LBLUE,

        LGREEN,

        LCYAN,

        LRED,

        LMAGENTA,

        YELLOW,

        BWHITE,

        NUM_VGA_COLORS};

 

 

 

 

 

/* our working copy of the apple II double hires colors */

/* this is in Apple II order */

uchar rgbArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

  0,   0,   0,    /* black    */

208,   0,  48,    /* red      */

  0,   0, 128,    /* dk blue  */

255,   0, 255,    /* purple   */

  0, 128,   0,    /* dk green */

128, 128, 128,    /* gray     */

  0,   0, 255,    /* med blue */

 96, 160, 255,    /* lt blue  */

128,  80,   0,    /* brown    */

255, 128,   0,    /* orange   */

192, 192, 192,    /* grey     */

255, 144, 128,    /* pink     */

  0, 255,   0,    /* lt green */

255, 255,   0,    /* yellow   */

 64, 255, 144,    /* aqua     */

255, 255, 255};   /* white    */

 

 

uchar BMP_header[] ={

0x42, 0x4D, 0x36, 0x76, 0x02, 0x00, 0x00, 0x00,

0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,

0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0xC0, 0x00,

0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x76, 0x02, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

 

 

/* Apple 2 Double Hires Format */

 

/* provides base address for page1 hires scanlines  */

unsigned HB[]={

0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,

0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,

0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,

0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,

0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,

0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,

0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,

0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,

0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,

0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,

0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,

0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,

0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,

0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,

0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,

0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,

0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,

0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,

0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,

0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,

0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,

0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,

0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,

0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0};

 

 

unsigned char dhrbuf[16384];

 

/*

 

The following is logically reordered to match the lores

color order...

 

                                                Repeated

                                                Binary

          Color         aux1  main1 aux2  main2 Pattern

          Black          00    00    00    00    0000

          Magenta        08    11    22    44    0001

              Dark Blue      11    22    44    08    1000

          Violet         19    33    66    4C    1001

          Dark Green     22    44    08    11    0100

          Grey1          2A    55    2A    55    0101

          Medium Blue    33    66    4C    19    1100

          Light Blue     3B    77    6E    5D    1101

          Brown          44    08    11    22    0010

          Orange         4C    19    33    66    0011

          Grey2          55    2A    55    2A    1010

          Pink           5D    3B    77    6E    1011

          Green          66    4C    19    33    0110

          Yellow         6E    5D    3B    77    0111

          Aqua           77    6E    5D    3B    1110

          White          7F    7F    7F    7F    1111

 

 

 

 

 

*/

 

/*

 

#define LOBLACK         0

#define LORED           1

#define LODKBLUE 2

#define LOPURPLE        3

#define LODKGREEN 4

#define LOGRAY          5

#define LOMEDBLUE 6

#define LOLTBLUE 7

#define LOBROWN         8

#define LOORANGE        9

#define LOGREY          10

#define LOPINK          11

#define LOLTGREEN 12

#define LOYELLOW        13

#define LOAQUA          14

#define LOWHITE         15

 

*/

 

/* the following array is based on the above */

unsigned char dhrbytes[16][4] = {

      0x00,0x00,0x00,0x00,

      0x08,0x11,0x22,0x44,

      0x11,0x22,0x44,0x08,

      0x19,0x33,0x66,0x4C,

      0x22,0x44,0x08,0x11,

      0x2A,0x55,0x2A,0x55,

      0x33,0x66,0x4C,0x19,

      0x3B,0x77,0x6E,0x5D,

      0x44,0x08,0x11,0x22,

      0x4C,0x19,0x33,0x66,

      0x55,0x2A,0x55,0x2A,

      0x5D,0x3B,0x77,0x6E,

      0x66,0x4C,0x19,0x33,

      0x6E,0x5D,0x3B,0x77,

      0x77,0x6E,0x5D,0x3B,

      0x7F,0x7F,0x7F,0x7F};

 

 

/* a double hi-res pixel can occur at any one of 7 positions */

/* in a 4 byte block which spans aux and main screen memory */

/* the horizontal resolution is 140 pixels */

 

/* read 2 input files */

int read_binaux(uchar *basename)

{

 

      FILE *fp;

      uchar outfile[128];

 

    // the bsaved images are split into two files

    // the first file is loaded into aux mem

    sprintf(outfile,"%s.AUX",basename);

      fp = fopen(outfile,"rb");

      if (NULL == fp)return INVALID;

      fread(dhrbuf,1,8192,fp);

      fclose(fp);

 

    // the second file is loaded into main mem

    sprintf(outfile,"%s.BIN",basename);

      fp = fopen(outfile,"rb");

      if (NULL == fp)return INVALID;

      fread(&dhrbuf[8192],1,8192,fp);

      fclose(fp);

 

      return SUCCESS;

 

}

 

/* read one input file */

int read_2fc(uchar *basename)

{

      FILE *fp;

      uchar outfile[128];

 

    sprintf(outfile,"%s.2FC",basename);

      fp = fopen(outfile,"rb");

      if (NULL == fp)return INVALID;

      fread(dhrbuf,1,16384,fp);

      fclose(fp);

 

      return SUCCESS;

 

}

 

 

 

/* returns the Apple II Hires drawcolor 0-15 */

/* a double hi-res pixel can occur at any one of 7 positions */

/* in a 4 byte block which spans aux and main screen memory */

/* the horizontal resolution is 140 pixels */

int dhrgetpixel(int x,int y)

{

    int xoff, pattern, idx;

    unsigned char *ptraux, *ptrmain,c1, c2, d1, d2;

 

    pattern = (x%7);

      xoff = HB[y] + ((x/7) * 2);

    ptraux  = (unsigned char *) &dhrbuf[xoff-0x2000];

    ptrmain = (unsigned char *) &dhrbuf[xoff];

 

 

      switch(pattern)

      {

            /* left this here for reference

 

            unsigned char dhrpattern[7][4] = {

            0,0,0,0,

            0,0,0,1,

            1,1,1,1,

            1,1,2,2,

            2,2,2,2,

            2,3,3,3,

        3,3,3,3};

        */

 

        /* compare colors in the input file to color patterns and return drawcolor */

        /* somewhat inelegant but lazy to read and debug if a problem */

            case 0: c1 = ptraux[0] &0x0f;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][0] & 0x0f;

                          if (d1 == c1) return idx;

                        }

                    break;

            case 1: c1 = ptraux[0] & 0x70;

                    c2 = ptrmain[0] & 0x01;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][0] & 0x70;

                          d2 = dhrbytes[idx][1] & 0x01;

                          if (d1 == c1 && d2 == c2) return idx;

                        }

                    break;

            case 2: c1 = ptrmain[0] & 0x1e;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][1] & 0x1e;

                          if (d1 == c1) return idx;

                        }

                    break;

            case 3: c1 = ptrmain[0] & 0x60;

                    c2 = ptraux[1] & 0x03;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][1] & 0x60;

                          d2 = dhrbytes[idx][2] & 0x03;

                          if (d1 == c1 && d2 == c2) return idx;

                        }

                break;

            case 4: c1 = ptraux[1] & 0x3c;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][2] & 0x3c;

                          if (d1 == c1) return idx;

                        }

                    break;

            case 5: c1 = ptraux[1] & 0x40;

                    c2 = ptrmain[1] & 0x07;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][2] & 0x40;

                          d2 = dhrbytes[idx][3] & 0x07;

                          if (d1 == c1 && d2 == c2) return idx;

                        }

                break;

            case 6: c1 = ptrmain[1] & 0x78;

                    for (idx = 0; idx < 16; idx++) {

                          d1 = dhrbytes[idx][3] & 0x78;

                          if (d1 == c1) return idx;

                        }

                    break;

      }

 

    return INVALID;

 

}

 

 

int save_to_bmp24(uchar *basename)

{

 

    FILE *fp;

    uchar outfile[128], tempr, tempg, tempb;

      int x,y,y2,idx;

 

 

    sprintf(outfile,"%s.BMP",basename);

      fp = fopen(outfile,"wb");

      if (NULL == fp)return INVALID;

 

/* write header for 280 x 192 x 24 bit bmp */

    fwrite(BMP_header,1,sizeof(BMP_header),fp);

 

 

/* write rgb triples and double each pixel to preserve the apsect ratio */

 

/* use the same color palette that is used in BMPA2FC and in our 24 bit Canvas file */

/* these can easily be pasted into a Canvas for conversion back to Apple II after editing */

/* provided of course that the palette is adhered to and not mucked-with or embellished. */

/* I'll refrain from making comments about idiots except to say that if one writes a program that */

/* even idiots can use then very likely only idiots will use it. */

 

 

    y2 = 191;

      for (y = 0; y< 192; y++) {

 

         for (x = 0; x < 140; x++) {

              idx = dhrgetpixel(x,y2);

 

          // range check

          if (idx < 0 || idx > 15)idx = 0; // default black

 

              tempr = rgbArray[idx][0];

              tempg = rgbArray[idx][1];

              tempb = rgbArray[idx][2];

 

              /* reverse order */

              fputc(tempb, fp);

              fputc(tempg, fp);

              fputc(tempr, fp);

 

              /* double-up */

              fputc(tempb, fp);

              fputc(tempg, fp);

              fputc(tempr, fp);

         }

         y2 -= 1;

    }

 

    return SUCCESS;

 

}

 

 

void main(int argc, char **argv)

{

  int status = 0;

 

 

  uchar fname[128],sname[128],outfile[128];

  uchar *wordptr;

  uchar scratchbuf[128];

  FILE *fp;

 

  if(argc == 1) {

    puts(szTextTitle);

    puts("Command line Usage is \"A2FCBMP MyHires.2FC\"");

    puts("                      \"A2FCBMP MyHires.BIN\"");

    puts("                      \"A2FCBMP MyHires.AUX\"");

    puts("                      \"A2FCBMP MyHires.2FC OutfileBaseName\"");

    puts("                      \"A2FCBMP MyHires.BIN OutfileBaseName\"");

    puts("                      \"A2FCBMP MyHires.AUX OutfileBaseName\"");

    puts("If converting .BIN and .AUX file pairs, both must be present.");

    printf("Enter Input FileName (Blank to Exit): ");

    gets(fname);

    if (fname[0] == ASCIIZ)

      exit(1);

    printf("Enter Output FileBaseName (Blank for None) : ");

    gets(outfile);

  }

  else {

    strcpy(fname, argv[1]);

    if (argc > 2)

      strcpy(outfile, argv[2]);

    else

      outfile[0] = ASCIIZ;

  }

 

  strcpy(sname, fname);

  wordptr = strtok(sname, ".");

  if (outfile[0] == ASCIIZ)strcpy(outfile,sname);

 

  status = read_binaux(sname);

  if(status)status = read_2fc(sname);

  if (status) {

    puts(szTextTitle);

    printf("%s is an Unsupported Format or cannot be opened.\n", fname);

    exit(1);

  }

 

 status = save_to_bmp24(outfile);

 if (status == SUCCESS)printf("%s.BMP Saved!\n",outfile);

 else printf("Error saving %s.BMP!\n",outfile);

 puts("[1]Have a Nice Dos![1]");

 exit(0);

 

}