/* ------------------------------------------------------------------------ */
/* 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);
}