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

/* BMPA2FC.C (C) Copyright Bill Buckels 2009, 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 to                 */

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

/*                from IBM-PC graphics files in the following formats:      */

/*                                                                          */

/*                CGA 320 x 200 x 4 color BASIC BSAVED IMAGE (.BAS) Files   */

/*                CGA 320 x 200 x 4 color ZSOFT .PCX Files                  */

/*                        EGA 320 x 200 x 16 color Windows .BMP Files       */

/*                RGB 320 x 400 x 24 Bit Windows .BMP "Canvas" Files        */

/*                (note: Only the top half of the canvas is displayed.      */

/*                       The bottom half is the required palette.           */

/*                                                                          */

/* Revision     : 1.0 First Release                                         */

/*                2.0 Added support for 24 bit Canvas Files.                */

/*                    Added support for ramfont for newer computers.        */

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

/* 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 <fcntl.h>

#include <string.h>

#include <dos.h>

#include <bios.h>

#include <io.h>

#include <malloc.h>

#include <conio.h>

 

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

/* Declarations, Vars. etc.                                                 */

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

 

typedef unsigned char     uchar;

typedef unsigned int      uint;

typedef unsigned long     ulong;

 

uchar *szTitle[]= {

"                                   ",

" BMPA2FC(C) Version 2.0            ",

" Copyright Bill Buckels 2012       ",

" All Rights Reserved.              ",

" Distributed as FreeWare.          ",

" Email: bbuckels@escape.ca         ",

"                                   ",

" Press Any Key To Continue...      ",

" --------------------------------- ",

" To Position Clip Box - Arrow Keys ",

" Page Up, Page Down, Home, and End ",

"                                   ",

" 'X' to toggle Scaling             ",

" 'S' or [ENTER] to  Save           ",

" 'Q' or [ESC] to Quit              ",

" 'H' For Help                      ",

"                                   ",

" 0-9 Toggle Color (Numeric Keys)   ",

" A-F Toggle Color (Alpha Keys)     ",

"                                   ",

NULL};

 

uchar *szTextTitle =

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

    "All Rights Reserved.";

 

#define TRUE     1

#define FALSE    0

#define SUCCESS  0

#define VALID    SUCCESS

#define FAILURE  -1

#define INVALID  FAILURE

 

#define MCGA '\x13'

#define TEXT '\x03'

 

#define ASCIIZ     '\x00'

#define CRETURN    '\r'

#define LFEED      '\n'

 

#define ENTERKEY   '\x0d' /* character generated by the Enter Key          */

#define ESCKEY     '\x1b' /* character generated by the Esc key            */

#define FUNCKEY    '\x00' /* first character generated by function keys    */

#define UPARROW    'H'    /* second character generated by up-arrow key    */

#define DOWNARROW  'P'    /* second character generated by down-arrow key  */

#define LTARROW    'K'    /* second character generated by left-arrow key  */

#define RTARROW    'M'    /* second character generated by right-arrow key */

#define PGUP       'I'    /* second character generated by page up key     */

#define PGDOWN     'Q'    /* second character generated by page down key   */

#define HOMEKEY    'G'    /* second character generated by home key        */

#define ENDKEY     'O'    /* second character generated by end key         */

 

/* second character generated by numerical fkeys */

/* starting at character 59                      */

/* ending at character 68                        */

#define F1         ';'

#define F2         '<'

#define F3         '='

#define F4         '>'

#define F5         '?'

#define F6         '@'

#define F7         'A'

#define F8         'B'

#define F9         'C'

#define F10        'D'

 

#define FRAMESIZE ((unsigned)64000)

#define FRAMEADDR ((uchar *)0xa0000000l)

 

/* middle of screen */

#define XMIN 0

#define YMIN 0

#define XMOS 159

#define YMOS 99

#define XMAX 319

#define YMAX 199

 

#define SCREENWIDTH  (XMAX + 1)

#define RASTERWIDTH  SCREENWIDTH

#define SCREENHEIGHT (YMAX + 1)

#define CELL_SIZE    8

 

 

// some "helpful" macros

 

#define vload() memcpy(FRAMEADDR,(uchar *)&rawbuffer[0],FRAMESIZE)

#define vsave() memcpy((uchar *)&rawbuffer[0],FRAMEADDR,FRAMESIZE)

#define zap(x) memset(FRAMEADDR,x,FRAMESIZE)

#define getpixel(x,y) rawbuffer[(y*RASTERWIDTH)+x]

 

 

// function prototypes

 

uchar GetMcgaPaletteIndex(uint cgacolor),

      lsb(uint),

      msb(uint),

      SetCrtMode(uchar);

 

uint byteword(uchar, uchar);

 

int BMP16_Read(uchar *),

    BSAVE_Read(uchar *),

    CheckForCGAPCX(uchar *),

    EatKeys(),

    GetVGAIndex(uchar, uchar, uchar),

    LoadPalette(void),

    MakeBMP(uchar *, uchar *),

    PCX_Read(uchar *),

    savedhrfragment(uchar *, int, int, int);

 

void dhrplot(int,int,uchar),

     LineBox(int, int, int, int, uint),

     PCMidFont(uchar *, int, int, int, int, int),

     PCRamFont(uchar *, int, int, int, int, int),

     PutPixel(int, int, uint, uchar *),

     SetPalette(),

     ShowTitle(void),

     TogglePalette(uchar),

     XBox(int, int, int, int),

     XPixel(int, int, uchar *);

 

uchar outlinecolor;

uchar drawcolor;

uchar *rawbuffer;

 

 

#define NUM_MCGA_COLORS    256

#define NUM_RGB_COLORS     3

 

uchar rgbinfo[NUM_MCGA_COLORS][NUM_RGB_COLORS];  /* the vga palette */

 

enum {  BLACK = 0,

        BLUE,

        GREEN,

        CYAN,

        RED,

        MAGENTA,

        BROWN,

        WHITE,

        GRAY,

        LBLUE,

        LGREEN,

        LCYAN,

        LRED,

        LMAGENTA,

        YELLOW,

        BWHITE,

        NUM_VGA_COLORS};

 

 

/* the following 4 palettes are used to troll

   for standard colors in the order given below */

 

/* 16 Color BMP style palette (probably PBRUSH from Windows 3.1) */

unsigned char rgbBmpArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

0x00, 0x00, 0x00,    // BLACK

0x00, 0x00, 0xBF,    // BLUE

0x00, 0xBF, 0x00,    // GREEN

0x00, 0xBF, 0xBF,    // CYAN

0xBF, 0x00, 0x00,    // RED

0xBF, 0x00, 0xBF,    // MAGENTA

0xBF, 0xBF, 0x00,    // BROWN

0xC0, 0xC0, 0xC0,    // WHITE

0x80, 0x80, 0x80,    // GRAY

0x00, 0x00, 0xFF,    // LBLUE

0x00, 0xFF, 0x00,    // LGREEN

0x00, 0xFF, 0xFF,    // LCYAN

0xFF, 0x00, 0x00,    // LRED

0xFF, 0x00, 0xFF,    // LMAGENTA

0xFF, 0xFF, 0x00,    // YELLOW

0xFF, 0xFF, 0xFF};   // BWHITE

 

/* 16 Color BMP style palette (Windows XP) */

/* notice that these johnny-come-latelies reversed GRAY and WHITE */

unsigned char rgbXmpArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

0x00, 0x00, 0x00,        // BLACK

0x00, 0x00, 0x80,        // BLUE

0x00, 0x80, 0x00,        // GREEN

0x00, 0x80, 0x80,        // CYAN

0x80, 0x00, 0x00,        // RED

0x80, 0x00, 0x80,        // MAGENTA

0x80, 0x80, 0x00,        // BROWN

0x80, 0x80, 0x80,        // GRAY

0xC0, 0xC0, 0xC0,        // WHITE

0x00, 0x00, 0xFF,        // LBLUE

0x00, 0xFF, 0x00,        // LGREEN

0x00, 0xFF, 0xFF,        // LCYAN

0xFF, 0x00, 0x00,        // LRED

0xFF, 0x00, 0xFF,        // LMAGENTA

0xFF, 0xFF, 0x00,        // YELLOW

0xFF, 0xFF, 0xFF};      // BWHITE

 

// VGA Palette

unsigned char rgbVgaArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

0x00, 0x00, 0x00,            /* BLACK    */

0x00, 0x00, 0xFF,            /* BLUE     */

0x00, 0xFF, 0x00,            /* GREEN    */

0x00, 0xFF, 0xFF,            /* CYAN     */

0xFF, 0x00, 0x00,            /* RED      */

0xFF, 0x00, 0xFF,            /* MAGENTA  */

0xFF, 0xFF, 0x00,            /* BROWN    */

0xC0, 0xC0, 0xC0,            /* WHITE    */

0x55, 0x55, 0x55,            /* GRAY     */

0x55, 0x55, 0xFF,            /* LBLUE    */

0x55, 0xFF, 0x55,            /* LGREEN   */

0x55, 0xFF, 0xFF,            /* LCYAN    */

0xFF, 0x55, 0x55,            /* LRED     */

0xFF, 0x55, 0xFF,            /* LMAGENTA */

0xFF, 0xFF, 0x55,            /* YELLOW   */

0xFF, 0xFF, 0xFF};           /* BWHITE   */

 

// 16 color ZSOFT PCPAINT PCX style palette

unsigned char rgbPcxArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

0x00, 0x00, 0x00,            /* BLACK    */

0x00, 0x00, 0xAA,            /* BLUE     */

0x00, 0xAA, 0x00,            /* GREEN    */

0x00, 0xAA, 0xAA,            /* CYAN     */

0xAA, 0x00, 0x00,            /* RED      */

0xAA, 0x00, 0xAA,            /* MAGENTA  */

0xAA, 0xAA, 0x00,            /* BROWN    */

0xAA, 0xAA, 0xAA,            /* WHITE    */

0x55, 0x55, 0x55,            /* GRAY     */

0x55, 0x55, 0xFF,            /* LBLUE    */

0x55, 0xFF, 0x55,            /* LGREEN   */

0x55, 0xFF, 0xFF,            /* LCYAN    */

0xFF, 0x55, 0x55,            /* LRED     */

0xFF, 0x55, 0xFF,            /* LMAGENTA */

0xFF, 0xFF, 0x55,            /* YELLOW   */

0xFF, 0xFF, 0xFF};           /* BWHITE   */

 

 

/* this palette is in the actual apple II lores color order */

/* this shows us approximately what we will end-up with */

uchar rgbDoubleHiresArray[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    */

 

#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

 

unsigned char VGAtoApple[NUM_VGA_COLORS]={

      LOBLACK,

      LODKBLUE,

      LODKGREEN,

      LOMEDBLUE,

      LORED,

      LOPURPLE,

      LOBROWN,

      LOGREY,

      LOGRAY,

      LOLTBLUE,

      LOLTGREEN,

      LOAQUA,

      LOORANGE,

      LOPINK,

      LOYELLOW,

      LOWHITE};

 

// to rollback the colors in case we can't automatically assign

unsigned char VGAtoAppleSaved[NUM_VGA_COLORS]={

      LOBLACK,

      LODKBLUE,

      LODKGREEN,

      LOMEDBLUE,

      LORED,

      LOPURPLE,

      LOBROWN,

      LOGREY,

      LOGRAY,

      LOLTBLUE,

      LOLTGREEN,

      LOAQUA,

      LOORANGE,

      LOPINK,

      LOYELLOW,

      LOWHITE};

 

 

/* 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    */

 

/* 16 Color VGA style palettes with RGB values

   from corresponding Apple II double hires colors */

unsigned char rgbOriginalArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

  0,   0,   0,    // BLACK    - black

  0,   0, 128,    // BLUE     - dk blue

  0, 128,   0,    // GREEN    - dk green

  0,   0, 255,    // CYAN     - med blue

208,   0,  48,    // RED      - red

255,   0, 255,    // MAGENTA  - purple

128,  80,   0,    // BROWN    - brown

192, 192, 192,    // WHITE    - grey

128, 128, 128,    // GRAY     - gray

 96, 160, 255,    // LBLUE    - lt blue

  0, 255,   0,    // LGREEN   - lt green

 64, 255, 144,    // LCYAN    - aqua

255, 128,   0,    // LRED     - orange

255, 144, 128,    // LMAGENTA - pink

255, 255,   0,    // YELLOW   - yellow

255, 255, 255};   // BWHITE   - white

 

unsigned char rgbCanvasArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={

  0,   0,   0,    // BLACK    - black

  0,   0, 128,    // BLUE     - dk blue

  0, 128,   0,    // GREEN    - dk green

  0,   0, 255,    // CYAN     - med blue

208,   0,  48,    // RED      - red

255,   0, 255,    // MAGENTA  - purple

128,  80,   0,    // BROWN    - brown

192, 192, 192,    // WHITE    - grey

128, 128, 128,    // GRAY     - gray

 96, 160, 255,    // LBLUE    - lt blue

  0, 255,   0,    // LGREEN   - lt green

 64, 255, 144,    // LCYAN    - aqua

255, 128,   0,    // LRED     - orange

255, 144, 128,    // LMAGENTA - pink

255, 255,   0,    // YELLOW   - yellow

255, 255, 255};   // BWHITE   - white

 

 

enum {  CGA_BLACK = 0,

        CGA_CYAN,

        CGA_MAGENTA,

        CGA_WHITE,

        NUM_CGA_COLORS};

 

/* a microsoft compatible bsaved image format descriptor */

uchar BSAVED_header[7]={

    '\xfd','\x00','\xb8','\x00','\x00','\x00','\x40'};

 

 

/* bmiHeader.biClrUsed and bmiHeader.biClrImportant fields

   will vary depending on the process that created the bmp

   but the other fields (below) should be invariant. */

uchar BMP_checkheader[] ={

0x42, 0x4D, 0x76, 0x7D, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00,

0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xC8, 0x00,

0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00,

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

 

 

/* canvas header for 320 x 400 x 24 bit BMP */

uchar BMP24_checkheader[] ={

0x42, 0x4D, 0x36, 0xDC, 0x05, 0x00, 0x00, 0x00,

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

0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x90, 0x01,

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

0x00, 0x00, 0x00, 0xDC, 0x05, 0x00, 0x00, 0x00,

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

 

/* header for 280 x 192 x 24 bit BMP */

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};

 

/* canvas header for 280 x 384 x 24 bit BMP */

uchar BMP280_header[] ={

0x42, 0x4D, 0x36, 0xEC, 0x04, 0x00, 0x00, 0x00,

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

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

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

0x00, 0x00, 0x00, 0xEC, 0x04, 0x00, 0x00, 0x00,

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

 

 

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

/* Low Level Video Routines, drawing routines, etc.                         */

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

 

uchar SetCrtMode(uchar vidmode)

{

  union REGS inregs, outregs;

 

  /* set mode */

  inregs.h.ah = 0;

  inregs.h.al = vidmode;

  int86(0x10, &inregs, &outregs);

 

  /* get mode */

  inregs.h.ah = 0xf;

  int86(0x10, &inregs, &outregs);

 

  /* return mode */

  return outregs.h.al;

 

}

 

int LoadPalette()

{

  union REGS regs;

  struct SREGS segregs;

 

  regs.h.ah = 0x10;                    /* fuction 10h */

  regs.h.al = 0x12;

  /* subfunction 12h - set block of color registers */

  regs.x.bx = 0;                       /* start with this reg */

  regs.x.cx = NUM_MCGA_COLORS;         /* do this many */

  regs.x.dx = (uint)rgbinfo;   /* offset to array */

  segregs.es = (uint)((long)rgbinfo >> 16);

  /* segment of array */

  int86x(0x10, &regs, &regs, &segregs);/* dump data to color registers */

 

  return SUCCESS;

 

}

 

 

 

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

/* Write a pixel at x,y using color                                       */

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

void PutPixel(int x, int y,uint pixelvalue, uchar *framebuffer)

{

    if (x<XMIN || x>XMAX || y<YMIN || y>YMAX)

      return;

 

    framebuffer[(y*RASTERWIDTH)+x]=(uchar)pixelvalue;

}

 

 

void XPixel(int x, int y, uchar *framebuffer)

{

 

    if (x<XMIN || x>XMAX || y<YMIN || y>YMAX)

      return;

 

    framebuffer[(y*RASTERWIDTH)+x] = framebuffer[(y*RASTERWIDTH)+x]^0xff;

}

 

 

void XBox(int x1, int y1, int x2, int y2)

{

   int x, y;

 

   for (x = x1; x <= x2; x++)XPixel(x, y1, FRAMEADDR);

   for (y = (y1+1); y < y2; y++) {

     XPixel(x1, y, FRAMEADDR);

     XPixel(x2, y, FRAMEADDR);

   }

   for (x = x1; x <= x2; x++)XPixel(x, y2, FRAMEADDR);

   return;

}

 

 

void LineBox(int x1, int y1, int x2, int y2, uint pixelvalue)

{

   int x, y;

 

   for (x = x1; x <= x2; x++)PutPixel(x, y1, pixelvalue, FRAMEADDR);

   for (y = (y1+1); y < y2; y++) {

     PutPixel(x1, y, pixelvalue, FRAMEADDR);

     PutPixel(x2, y, pixelvalue, FRAMEADDR);

   }

   for (x = x1; x <= x2; x++)PutPixel(x, y2, pixelvalue, FRAMEADDR);

   return;

}

 

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

/* PCRamFont                                                              */

/* A template for a bitmap font.                                          */

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

unsigned char ramfont[] = {

0,0,0,0,0,0,0,0,

126,129,165,129,189,153,129,126,

124,254,214,186,198,254,124,0,

198,238,254,254,124,56,16,0,

16,56,124,254,124,56,16,0,

16,56,16,238,238,16,56,0,

56,124,254,254,108,16,56,0,

56,124,254,254,108,16,56,0,

255,231,195,129,195,231,255,255,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,

62,62,54,54,246,102,30,12,

219,60,102,231,102,60,219,0,

128,192,240,248,240,192,128,0,

2,6,30,62,30,6,2,0,

24,60,126,24,126,60,24,0,

102,102,102,102,102,0,102,0,

127,219,123,59,27,27,27,0,

60,102,56,108,108,56,204,120,

0,0,0,0,254,254,254,0,

24,60,126,24,126,60,24,126,

24,60,126,24,24,24,24,0,

24,24,24,24,126,60,24,0,

0,24,28,254,28,24,0,0,

0,48,112,254,112,48,0,0,

0,48,112,254,112,48,0,0,

0,48,112,254,112,48,0,0,

0,48,112,254,112,48,0,0,

0,48,112,254,112,48,0,0,

0,0,0,0,0,0,0,0,

24,60,60,24,24,0,24,0,

108,108,108,0,0,0,0,0,

108,108,254,108,254,108,108,0,

24,126,192,124,6,252,24,0,

0,198,12,24,48,96,198,0,

56,108,56,118,204,204,118,0,

24,24,48,0,0,0,0,0,

24,48,96,96,96,48,24,0,

96,48,24,24,24,48,96,0,

0,238,124,254,124,238,0,0,

0,24,24,126,24,24,0,0,

0,0,0,0,24,24,48,0,

0,0,0,254,0,0,0,0,

0,0,0,0,0,56,56,0,

6,12,24,48,96,192,128,0,

124,198,206,222,246,230,124,0,

24,120,24,24,24,24,126,0,

124,198,12,24,48,102,254,0,

124,198,6,60,6,198,124,0,

12,28,60,108,254,12,12,0,

254,192,252,6,6,198,124,0,

124,198,192,252,198,198,124,0,

254,198,6,12,24,24,24,0,

124,198,198,124,198,198,124,0,

124,198,198,126,6,198,124,0,

0,28,28,0,0,28,28,0,

0,24,24,0,0,24,24,48,

12,24,48,96,48,24,12,0,

0,0,254,0,0,254,0,0,

96,48,24,12,24,48,96,0,

124,198,6,12,24,0,24,0,

124,198,198,222,220,192,126,0,

56,108,198,198,254,198,198,0,

252,102,102,124,102,102,252,0,

60,102,192,192,192,102,60,0,

248,108,102,102,102,108,248,0,

254,194,192,248,192,194,254,0,

254,98,96,124,96,96,240,0,

124,198,192,192,222,198,124,0,

198,198,198,254,198,198,198,0,

60,24,24,24,24,24,60,0,

60,24,24,24,216,216,112,0,

198,204,216,240,216,204,198,0,

240,96,96,96,96,98,254,0,

198,238,254,214,214,198,198,0,

198,230,230,246,222,206,198,0,

124,198,198,198,198,198,124,0,

252,102,102,124,96,96,240,0,

124,198,198,198,198,214,124,6,

252,198,198,252,216,204,198,0,

124,198,192,124,6,198,124,0,

126,90,24,24,24,24,60,0,

198,198,198,198,198,198,124,0,

198,198,198,198,108,56,16,0,

198,198,214,214,254,238,198,0,

198,108,56,56,56,108,198,0,

102,102,102,60,24,24,60,0,

254,134,12,24,48,98,254,0,

124,96,96,96,96,96,124,0,

192,96,48,24,12,6,2,0,

124,12,12,12,12,12,124,0,

16,56,108,198,0,0,0,0,

0,0,0,0,0,0,0,255,

48,48,24,0,0,0,0,0,

0,0,120,12,124,204,126,0,

224,96,124,102,102,102,252,0,

0,0,124,198,192,198,124,0,

28,12,124,204,204,204,126,0,

0,0,124,198,254,192,124,0,

28,54,48,252,48,48,120,0,

0,0,118,206,198,126,6,124,

224,96,124,102,102,102,230,0,

24,0,56,24,24,24,60,0,

12,0,28,12,12,12,204,120,

224,96,102,108,120,108,230,0,

56,24,24,24,24,24,60,0,

0,0,108,254,214,214,198,0,

0,0,220,102,102,102,102,0,

0,0,124,198,198,198,124,0,

0,0,220,102,102,124,96,240,

0,0,118,204,204,124,12,30,

0,0,220,102,96,96,240,0,

0,0,124,192,124,6,124,0,

48,48,252,48,48,54,28,0,

0,0,204,204,204,204,118,0,

0,0,198,198,108,56,16,0,

0,0,198,198,214,254,108,0,

0,0,198,108,56,108,198,0,

0,0,198,198,206,118,6,124,

0,0,252,152,48,100,252,0,

14,24,24,112,24,24,14,0,

24,24,24,0,24,24,24,0,

112,24,24,14,24,24,112,0,

118,220,0,0,0,0,0,0,

0,16,56,56,108,108,254,0,

60,102,192,102,60,24,204,120,

0,198,0,198,198,206,118,0,

14,0,124,198,254,192,124,0,

124,198,120,12,124,204,126,0,

198,0,120,12,124,204,126,0,

224,0,120,12,124,204,126,0,

56,56,120,12,124,204,126,0,

0,0,124,192,124,24,108,56,

124,198,124,198,254,192,124,0,

198,0,124,198,254,192,124,0,

224,0,124,198,254,192,124,0,

102,0,56,24,24,24,60,0,

124,198,56,24,24,24,60,0,

224,0,56,24,24,24,60,0,

198,56,108,198,254,198,198,0,

56,56,0,124,198,254,198,0,

14,0,254,192,248,192,254,0,

0,0,108,154,126,216,110,0,

126,216,216,254,216,216,222,0,

124,198,0,124,198,198,124,0,

0,198,0,124,198,198,124,0,

0,224,0,124,198,198,124,0,

124,198,0,198,198,206,118,0,

0,224,0,198,198,206,118,0,

0,198,0,198,206,118,6,124,

198,56,108,198,198,108,56,0,

198,0,198,198,198,198,124,0,

0,24,126,216,216,126,24,0,

56,108,96,240,102,246,108,0,

195,102,60,126,24,60,24,0,

252,198,252,204,222,204,206,0,

12,30,24,126,24,24,216,112,

14,0,120,12,124,204,126,0,

28,0,56,24,24,24,60,0,

0,14,0,124,198,198,124,0,

0,14,0,204,204,220,118,0,

0,252,0,188,102,102,230,0,

254,0,198,230,246,206,198,0,

56,108,62,0,126,0,0,0,

124,198,124,0,124,0,0,0,

24,0,24,48,96,102,60,0,

0,0,0,124,96,96,0,0,

0,0,0,124,12,12,0,0,

192,204,216,48,124,54,12,62,

192,204,216,48,108,60,126,12,

24,0,24,24,60,60,24,0,

0,54,108,216,108,54,0,0,

0,216,108,54,108,216,0,0,

34,136,34,136,34,136,34,136,

85,170,85,170,85,170,85,170,

221,119,221,119,221,119,221,119,

24,24,24,24,24,24,24,24,

24,24,24,24,248,24,24,24,

24,24,248,24,248,24,24,24,

54,54,54,54,246,54,54,54,

0,0,0,0,254,54,54,54,

0,0,248,24,248,24,24,24,

54,54,246,6,246,54,54,54,

54,54,54,54,54,54,54,54,

0,0,254,6,246,54,54,54,

54,54,246,6,254,0,0,0,

54,54,54,54,254,0,0,0,

24,24,248,24,248,0,0,0,

0,0,0,0,248,24,24,24,

24,24,24,24,31,0,0,0,

24,24,24,24,255,0,0,0,

0,0,0,0,255,24,24,24,

24,24,24,24,31,24,24,24,

0,0,0,0,255,0,0,0,

24,24,24,24,255,24,24,24,

24,24,31,24,31,24,24,24,

54,54,54,54,55,54,54,54,

54,54,55,48,63,0,0,0,

0,0,63,48,55,54,54,54,

54,54,247,0,255,0,0,0,

0,0,255,0,247,54,54,54,

54,54,55,48,55,54,54,54,

0,0,255,0,255,0,0,0,

54,54,247,0,247,54,54,54,

24,24,255,0,255,0,0,0,

54,54,54,54,255,0,0,0,

0,0,255,0,255,24,24,24,

0,0,0,0,255,54,54,54,

54,54,54,54,63,0,0,0,

24,24,31,24,31,0,0,0,

0,0,31,24,31,24,24,24,

0,0,0,0,63,54,54,54,

54,54,54,54,255,54,54,54,

24,24,255,24,255,24,24,24,

24,24,24,24,248,0,0,0,

0,0,0,0,31,24,24,24,

255,255,255,255,255,255,255,255,

0,0,0,0,255,255,255,255,

240,240,240,240,240,240,240,240,

15,15,15,15,15,15,15,15,

255,255,255,255,0,0,0,0,

0,0,102,220,216,220,102,0,

120,204,248,204,230,220,192,0,

0,254,98,96,96,96,224,0,

0,254,108,108,108,108,108,0,

254,198,96,48,96,198,254,0,

0,126,216,204,204,216,112,0,

0,102,102,102,102,124,192,0,

0,118,220,24,24,24,56,0,

254,56,108,198,108,56,254,0,

56,108,198,254,198,108,56,0,

56,108,198,198,108,108,238,0,

62,96,56,102,198,204,120,0,

0,0,126,219,219,126,0,0,

6,124,222,246,230,124,192,0,

56,96,192,248,192,96,56,0,

124,198,198,198,198,198,198,0,

0,254,0,254,0,254,0,0,

24,24,126,24,24,0,126,0,

48,24,12,24,48,0,126,0,

12,24,48,24,12,0,126,0,

12,30,24,24,24,24,24,24,

24,24,24,24,24,120,48,0,

0,0,24,0,126,0,24,0,

0,118,220,0,118,220,0,0,

124,198,198,124,0,0,0,0,

0,0,0,24,24,0,0,0,

0,0,0,0,24,0,0,0,

31,24,24,24,248,56,24,0,

216,108,108,108,0,0,0,0,

112,216,48,248,0,0,0,0,

0,0,124,124,124,124,0,0,

0,0,124,124,124,124,0,0};

 

 

void PCRamFont(uchar *str,

               int xorigin, int yorigin, int scale,

               int fontcolor, int outlinecolor)

{

    int scanline,

        yreg=yorigin,

        xreg=xorigin,

        byt,

        character,

        nibble,

        color;

    int x,y;

 

    /* flags etcetera */

 

    int target = strlen(str);  /* string length */

 

    for (scanline=0;scanline<CELL_SIZE;scanline++)/* finish the current scanline*/

    {                                     /*  before advancing to the next*/

      for (byt=0;byt<target;byt++)     /* run the scanline*/

      {

        /* get the bitmap  */

        character = ramfont[(str[byt]&0x7f)*CELL_SIZE+scanline];

        for (nibble=0;nibble<CELL_SIZE;nibble++)

        {

          xreg+=scale;

          /* chew the byte to bits and lite the pixel if it's a swallow  */

          if (str[byt]!=CRETURN && str[byt]!=LFEED) {

            if (character & 0x80>>nibble)

              color = fontcolor;

            else

              color = outlinecolor;

            if (color > -1 ) {

              for (x=0; x!=scale; x++)

                for (y=0;y!=scale;y++)

                  PutPixel(xreg+x,yreg+y,color, FRAMEADDR);

            }

          }

        }

      }

      yreg+=scale;

      xreg=xorigin;

    }

 

}

 

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

/* PCMidFont                                                              */

/* Maps to PCRamFont, uses a centre-justified x-coordinate.               */

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

void PCMidFont(uchar *str, int xmiddle, int yorigin,

               int scale, int fontcolor, int outlinecolor)

{   /* centre justified string */

    PCRamFont(str,(xmiddle-(4*(strlen(str))*scale)),yorigin,scale,

              fontcolor, outlinecolor);

}

 

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

/* GetMcgaPalette is called during the loading of the input file.         */

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

uchar GetMcgaPaletteIndex(uint cgacolor)

{

 

  // I just hardcoded these in here for CGA images.

  // I couldn't see any point in getting too gancy with 4 colors

  // There isn't much hardship in toggling 4 colors anyway

  // My main target for automation was when a 16 color BMP is colored

  // in Windows Paint... then exported in this thing.

  uint uiIndex;

 

  switch(cgacolor) {

    case  CGA_WHITE:

          uiIndex = LOWHITE; break;

    case  CGA_MAGENTA:

          uiIndex = LORED; break;

    case  CGA_CYAN:

          uiIndex = LODKBLUE; break;

    case  CGA_BLACK:

    default:

          uiIndex = LOBLACK; break;

  }

  return (uchar)uiIndex;

}

 

 

void SetPalette()

{

 

  uint idx, x, temp;

 

      memset((uchar *)&rgbinfo[0][0], 0, (NUM_MCGA_COLORS*NUM_RGB_COLORS));

 

      /* Set the lightest and darkest color in the current palette.  */

      /* use the darkest color for the drawcolor                     */

      /* use the lightest color for the outline color                */

 

      drawcolor    = 254;

      outlinecolor = 255;

 

      // using 6 bit color model (VGA standard video uses 6 bits)

      // for the internal program. values are in the range 0-63

      rgbinfo[255][0] = rgbinfo[255][1] =  rgbinfo[255][2] = 63;

 

      // leave the drawcolor and outline colors alone

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

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

               temp = rgbArray[idx][x];

               rgbinfo[idx][x] = temp >> 2; // downshift to 6 bits of color

            }

      }

 

}

 

 

/* the following attempts to match BMP colors with a common palette */

/* that is to say... a basic default EGA style 16 color palette like */

/* the kind that Windows Paint provides as a lowest common denominator */

/* my rationale here is that if we can't automate the entire remapping */

/* we fail the whole sh*terree because otherwise we could start mashing */

/* two colors or more together and I for one would not care for that... */

int GetVGAIndex(uchar red, uchar green, uchar blue)

{

 

    int idx;

 

    // try exact match

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

            if (red == rgbCanvasArray[idx][0] && green == rgbCanvasArray[idx][1] && blue == rgbCanvasArray[idx][2])return idx;

      }

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

            if (red == rgbBmpArray[idx][0] && green == rgbBmpArray[idx][1] && blue == rgbBmpArray[idx][2])return idx;

      }

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

            if (red == rgbXmpArray[idx][0] && green == rgbXmpArray[idx][1] && blue == rgbXmpArray[idx][2])return idx;

      }

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

        if (red == rgbVgaArray[idx][0] && green == rgbVgaArray[idx][1] && blue == rgbVgaArray[idx][2])return idx;

      }

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

        if (red == rgbPcxArray[idx][0] && green == rgbPcxArray[idx][1] && blue == rgbPcxArray[idx][2])return idx;

      }

 

      // adjust gun values to match using EGA-like thresholds

      // this corresponds to the old PCX style palette

      if (red < 43) red = 0;         // 0x00

      else if (red < 128) red = 85;  // 0x55

      else if (red < 224) red = 170; // 0xaa

      else red = 255;                // 0xff

 

      if (green < 43) green = 0;

      else if (green < 128) green = 85;

      else if (green < 213) green = 170;

      else green = 255;

 

      if (blue < 43) blue = 0;

      else if (blue < 128) blue = 85;

      else if (blue < 213) blue = 170;

      else blue = 255;

 

    // try again

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

            if (red == rgbCanvasArray[idx][0] && green == rgbCanvasArray[idx][1] && blue == rgbCanvasArray[idx][2])return idx;

      }

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

            if (red == rgbBmpArray[idx][0] && green == rgbBmpArray[idx][1] && blue == rgbBmpArray[idx][2])return idx;

      }

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

            if (red == rgbXmpArray[idx][0] && green == rgbXmpArray[idx][1] && blue == rgbXmpArray[idx][2])return idx;

      }

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

        if (red == rgbVgaArray[idx][0] && green == rgbVgaArray[idx][1] && blue == rgbVgaArray[idx][2])return idx;

      }

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

        if (red == rgbPcxArray[idx][0] && green == rgbPcxArray[idx][1] && blue == rgbPcxArray[idx][2])return idx;

      }

      // if no match yet let them pick double hires color manually

    return INVALID;

}

 

 

int PaletteIndex[NUM_VGA_COLORS] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

 

void TogglePalette(uchar ch)

{

      /* after the initial remapping of colors by color order */

      /* it is very likely that not all entries will remap correctly */

      /* so the palette can be toggled to adjust this */

      int idx, jdx;

 

      ch = toupper(ch);

 

      switch(ch)

      {

            case 'A':

            case 'B':

            case 'C':

            case 'D':

            case 'E':

            case 'F':

              idx = ch - 55;

              break;

 

            default:

 

                if (ch < '0' || ch > '9')return;

                idx = ch - 48;

      }

 

      /* update remapping index */

    jdx = PaletteIndex[idx] + 1;

    if (jdx > 15)jdx = 0;

    PaletteIndex[idx] = jdx;

    /* update the working array */

    rgbArray[idx][0] = rgbDoubleHiresArray[jdx][0];

    rgbArray[idx][1] = rgbDoubleHiresArray[jdx][1];

    rgbArray[idx][2] = rgbDoubleHiresArray[jdx][2];

    /* update the visual */

    SetPalette();

    LoadPalette();

 

}

 

 

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

/* File Related Functions                                                 */

/* Image Loaders, Image Savers, etc.                                      */

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

 

/* type conversion functions */

uint byteword(uchar a, uchar b){

  return b << 8 | a;

}

uchar lsb(uint word){

  return word &0xff;

}

uchar msb(uint word){

  return word >> 8;

}

 

int CheckForCGAPCX(uchar *name)

{

  FILE *fp;

  /* reads a ZSOFT .PCX header but ignores the color map */

  int i;

  /* we only want CGA COLOR compatible full screens. */

 

  uchar pcxheader[128];

  uint zsoft,version,codetype,pixbits;

  uint xmin, ymin, xmax, ymax;

  uint x, y;

  uint no_planes, bytesperline;

  int status = VALID;

 

  /* read the file header */

  if((fp = fopen(name, "rb")) == NULL)return INVALID;

  for(i = 0;i < 128;i++)pcxheader[i] = fgetc(fp);

  fclose(fp);

 

  zsoft = pcxheader[0];

  version = pcxheader[1];

  codetype = pcxheader[2];

  pixbits = pcxheader[3];

 

  if(zsoft != 10)

    status = INVALID;

  if(codetype != 1)

    status = INVALID;

  if(pixbits != 2)        /* accept only CGA color images */

    status = INVALID;     /* monochrome images can't be mapped properly */

 

  xmin = byteword(pcxheader[4], pcxheader[5]);

  ymin = byteword(pcxheader[6], pcxheader[7]);

  xmax = byteword(pcxheader[8], pcxheader[9]);

  ymax = byteword(pcxheader[10], pcxheader[11]);

 

  no_planes = pcxheader[65];

  bytesperline = byteword(pcxheader[66], pcxheader[67]);

 

  x =  xmax - xmin;

  y =  ymax - ymin;

 

  if(x != XMAX)status = INVALID;

  if(y != YMAX)status = INVALID;

  if(no_planes != 1)status = INVALID;

  if(bytesperline != 80)status = INVALID;    /* full screens only */

 

  /* we can ignore the color map since we        */

  /* are limiting ourselves to CGA modes         */

  /* so we will not handle over 2-bits per pixel */

 

  return status;

 

}

 

int BSAVE_Read(uchar *name)

{

  int fh,fh2,y,i;

  uchar byte;

  uchar *crt;

  uchar namebuf[128];

  uchar headbuf[7];

  uchar linebuffer[80];

  long target = 16384l,target2,header = 7;

 

  /* open the file twice,eliminate the interleaf,read contiguous */

  sprintf(namebuf, "%s.BAS", name);

 

  if((fh = open(namebuf, O_RDONLY | O_BINARY)) == - 1)return INVALID;

 

  if((fh2 = open(namebuf, O_RDONLY | O_BINARY)) == - 1) {

    close(fh);

    return INVALID;

  }

 

  read(fh, headbuf, sizeof(BSAVED_header));

 

  /* only read the first 3 bytes, some of these are a little */

  /* different size, depending on how they were saved.       */

 

  for(i = 0;i < 3;i++)

    if(headbuf[i] != BSAVED_header[i]) {

      close(fh);

      close(fh2);

      return INVALID;

    }

 

  target2 = (target / 2) + header;

  lseek(fh, (long)(header), SEEK_SET)  ;

  lseek(fh2, (long)(target2), SEEK_SET);

 

  crt = (uchar *)&rawbuffer[0];

 

  /* translate from a 2 bit color pixel to an 8 bit color pixel */

 

  for(y = 0;y < SCREENHEIGHT;y += 2) {

    read(fh, linebuffer, 80);

    for(i = 0;i < 80;i++) {

      byte = linebuffer[i];

      *crt++ = GetMcgaPaletteIndex((byte >> 6));

      *crt++ = GetMcgaPaletteIndex((byte >> 4)&3);

      *crt++ = GetMcgaPaletteIndex((byte >> 2)&3);

      *crt++ = GetMcgaPaletteIndex((byte)&3);

    }

    read(fh2, linebuffer, 80);

    for(i = 0;i < 80;i++) {

      byte = linebuffer[i];

      *crt++ = GetMcgaPaletteIndex((byte >> 6));

      *crt++ = GetMcgaPaletteIndex((byte >> 4)&3);

      *crt++ = GetMcgaPaletteIndex((byte >> 2)&3);

      *crt++ = GetMcgaPaletteIndex((byte)&3);

    }

  }

  close(fh);

  close(fh2);

  return SUCCESS;

 

}

 

/* Translation for VGA to display CGA */

int PCX_Read(uchar *pcxfilename)

{

  uchar pcxheader[128];

  uchar *crt;

  uint packet;

  uchar bit[4];

  FILE *fp;

  uchar byte,bytecount;

  long wordcount,target;

  uchar name1[128], name2[128];

 

  sprintf(name1, "%s.PCX", pcxfilename);

 

  if(CheckForCGAPCX(name1) == - 1)return INVALID;

 

  if (NULL == (fp = fopen(name1, "rb")))return INVALID;

 

  target = filelength(fileno(fp));

  for(wordcount = 0;wordcount != 128;wordcount++)byte = fgetc(fp);

 

  crt = (uchar *)&rawbuffer[0];

 

  do {

    bytecount = 1;                     /* start with a seed count */

    byte = fgetc(fp);

    wordcount++;

    /* check to see if its raw */

    if(0xC0 == (0xC0 &byte)) {

      /* if its not, run encoded */

      bytecount = 0x3f &byte;

      byte = fgetc(fp);

      wordcount++;

    }

    /* translate from 2 bit pixel to 8 bit pixel */

 

    bit[0] = GetMcgaPaletteIndex((byte >> 6));

    bit[1] = GetMcgaPaletteIndex((byte >> 4)&3);

    bit[2] = GetMcgaPaletteIndex((byte >> 2)&3);

    bit[3] = GetMcgaPaletteIndex((byte)&3);

    packet = 0;

    while(packet++ < bytecount) {

      *crt++ = bit[0];

      *crt++ = bit[1];

      *crt++ = bit[2];

      *crt++ = bit[3];

    }

  }while(wordcount < target);

  fclose(fp);

  return(0);

}

 

 

 

int BMP16_Read(uchar *basename)

{

 

      uint temp, temp2;

      uchar *screenbuffer, bmpfile[128];

      int x, y;

      FILE *fp;

 

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

      fp=fopen(bmpfile,"rb");

 

      if (NULL == fp) return INVALID;

 

    /* check the invariant fields in the bmp header */

      for (x=0; x < sizeof(BMP_checkheader); x++) {

        temp2 = fgetc(fp);

        temp=BMP_checkheader[x];

        if (temp != temp2) {

            fclose(fp);

            return INVALID;

 

        }

      }

 

      /* ignore variant fields in header - 8 bytes */

      /* bmiHeader.biClrUsed and bmiHeader.biClrImportant */

      for (x=0; x < 8; x++)fgetc(fp);

 

      for(y=0;y<NUM_VGA_COLORS;y++)

      {

        /* RGB Quad Structure b,g,r,0 */

        for(x=3;x>0;x--)

        {

            temp = fgetc(fp);

            rgbOriginalArray[y][x-1] = temp;

 

        }

        fgetc(fp);

      }

 

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

            // attempt to reorganize remapping of the BMP

            // to the apple double hires palette based on rgb values

            x = GetVgaIndex(rgbOriginalArray[y][0],

                                    rgbOriginalArray[y][1],

                                    rgbOriginalArray[y][2]);

            // however, if all colors do not match then

            // we simply use the default color order

            // and let them manually select the apple double hires color

            if (x == INVALID) {

                for (x = 0; x < NUM_VGA_COLORS; x++)

                   VGAtoApple[x] = VGAtoAppleSaved[x];      // reset

                break;

 

            }

            /* move x to y for the remap of the image data */

            /* if they don't like it they can toggle the colors */

          VGAtoApple[y] = VGAtoAppleSaved[x];

 

      }

 

    /* remap the image to the equivalent apple2 double hires colors */

    /* to the best known equivalents */

      for (y = SCREENHEIGHT; y > 0; y--) {

        screenbuffer=(uchar *)&rawbuffer[((y-1)*SCREENWIDTH)];

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

            if (x % 2 == 0) {

              temp  = fgetc(fp);

              temp2 = (temp >> 4);

            }

            else {

              temp2 = (temp & 15);

            }

 

            screenbuffer[x] = VGAtoApple[temp2];

 

        }

      }

 

      fclose(fp);

 

 

      return SUCCESS;

 

}

 

 

int BMP24_Read(uchar *basename)

{

 

      uint temp, temp2;

      int tempr, tempg, tempb;

      uchar *screenbuffer, bmpfile[128];

      int x, y, z, x1, y1, canvas, can280;

      FILE *fp;

 

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

      fp=fopen(bmpfile,"rb");

 

      if (NULL == fp) return INVALID;

 

    canvas = INVALID;

    can280 = VALID;

 

    /* check the invariant fields in the bmp header */

      for (x=0; x < sizeof(BMP280_header); x++) {

        temp2 = fgetc(fp);

        temp=BMP280_header[x];

        if (temp != temp2) {

            can280 = INVALID;

            rewind(fp);

        break;

        }

      }

 

      if (can280 == INVALID) {

            /* check the invariant fields in the bmp header */

            for (x=0; x < sizeof(BMP_header); x++) {

              temp2 = fgetc(fp);

              temp=BMP_header[x];

              if (temp != temp2) {

                  canvas = VALID;

                  rewind(fp);

                  break;

              }

            }

      }

 

    if (canvas == VALID) {

            /* check the invariant fields in the bmp header */

            for (x=0; x < sizeof(BMP24_checkheader); x++) {

              temp2 = fgetc(fp);

              temp=BMP24_checkheader[x];

              if (temp != temp2) {

                  fclose(fp);

                  return INVALID;

 

              }

            }

      }

 

 

      /* ignore variant fields in header - 8 bytes */

      /* bmiHeader.biClrUsed and bmiHeader.biClrImportant */

      for (x=0; x < 8; x++)fgetc(fp);

 

    if (canvas == VALID) {

            for (y = SCREENHEIGHT; y > 0; y--) {

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

                    /* discard bottom 200 scanlines of canvas */

                    fgetc(fp);

                    fgetc(fp);

                    fgetc(fp);

                  }

            }

            /* remap the image to the equivalent apple2 double hires colors */

            /* to the best known equivalents */

            for (y = SCREENHEIGHT; y > 0; y--) {

              screenbuffer=(uchar *)&rawbuffer[((y-1)*SCREENWIDTH)];

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

                    tempb  = fgetc(fp);

                    tempg  = fgetc(fp);

                    tempr  = fgetc(fp);

                    z = GetVgaIndex((uchar)tempr,(uchar)tempg,(uchar)tempb);

                    if (z == INVALID) z = 0;

                    screenbuffer[x] = VGAtoApple[z];

              }

            }

    }

    else {

      memset(&rawbuffer[0],0,(unsigned)65000);

        /* bounds of hires image */

        if (can280 == VALID) {

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

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

                          /* discard bottom 192 scanlines of can280 */

                          fgetc(fp);

                          fgetc(fp);

                          fgetc(fp);

                        }

                  }

            }

            y1 = 195;

            for (y = 0; y < 192; y++,y1--) {

              screenbuffer=(uchar *)&rawbuffer[(y1*SCREENWIDTH)];

              x1 = 20;

              for (x = 0; x < 280; x++, x1++) {

                    tempb  = fgetc(fp);

                    tempg  = fgetc(fp);

                    tempr  = fgetc(fp);

                    z = GetVgaIndex((uchar)tempr,(uchar)tempg,(uchar)tempb);

                    if (z == INVALID) z = 0;

                    screenbuffer[x1] = VGAtoApple[z];

              }

            }

      }

      fclose(fp);

 

 

      return SUCCESS;

 

}

 

 

/* routines to save to 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 */

void dhrplot(int x,int y,uchar drawcolor)

{

    int xoff, pattern;

    unsigned char *ptraux, *ptrmain;

 

    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};

        */

 

            case 0: ptraux[0] |= dhrbytes[drawcolor][0] &0x0f;

                    break;

            case 1: ptraux[0] |= dhrbytes[drawcolor][0] & 0x70;

                    ptrmain[0] |= dhrbytes[drawcolor][1] & 0x01;

                    break;

            case 2: ptrmain[0] |= dhrbytes[drawcolor][1] & 0x1e;

                    break;

            case 3: ptrmain[0] |= dhrbytes[drawcolor][1] & 0x60;

                    ptraux[1] |= dhrbytes[drawcolor][2] & 0x03;

                break;

            case 4: ptraux[1] |= dhrbytes[drawcolor][2] & 0x3c;

                    break;

            case 5: ptraux[1] |= dhrbytes[drawcolor][2] & 0x40;

                    ptrmain[1] |= dhrbytes[drawcolor][3] & 0x07;

                    break;

            case 6: ptrmain[1] |= dhrbytes[drawcolor][3] & 0x78;

                    break;

      }

 

}

 

/* save 2 output files */

int savedhrfragment(uchar *basename, int x1, int y1, int dhrscale)

{

 

      FILE *fp;

      uchar outfile[128], temp, remap;

      int x,y,x2,y2;

 

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

      fp = fopen(outfile,"wb");

      if (NULL == fp)return INVALID;

 

      memset(dhrbuf,0,16384);

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

 

         /* double scanlines to preserve aspect ratio

            when not scaling */

         if (dhrscale == 1) y2 = ((y/2) + y1);

         else y2 = y + y1;

 

         /* skip every second pixel when scaling */

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

              if (dhrscale == 1) x2 = x + x1;

              else x2 = (x * 2) + x1;

              temp = getpixel(x2,y2);

              remap =  PaletteIndex[temp];

              dhrplot(x,y,remap);

         }

 

    }

 

      fwrite(dhrbuf,1,16384,fp);

      fclose(fp);

 

 

    // the bsaved images are split into two files

    // the first file is loaded into aux mem

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

      fp = fopen(outfile,"wb");

      if (NULL == fp)return INVALID;

      fwrite(dhrbuf,1,8192,fp);

      fclose(fp);

 

    // the second file is loaded into main mem

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

      fp = fopen(outfile,"wb");

      if (NULL == fp)return INVALID;

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

      fclose(fp);

 

      return SUCCESS;

}

 

 

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

/* User Input and helper functions and Main Program                         */

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

 

// eat keystrokes... avoid mindlessly cycling through the program

// if the user leans on the keyboard and doesn't budge for a moment.

// Any DOS program should do this...

 

int EatKeys()

{

  if (kbhit())

    while (kbhit())

      if (getch() == FUNCKEY)

         getch();

 

  return SUCCESS;

}

 

// show the title at startup and when 'H' (Help) is pressed.

void ShowTitle()

{

    int y, yorg, y1, x1, xx, c;

    uchar *ptr;

 

    for (y = 0; szTitle[y]!= NULL; y++);

    y+=2;

 

 

    yorg = y1 = ((SCREENHEIGHT - y*CELL_SIZE) / 2) - 1;

    for (y = 0; szTitle[y]!= NULL; y++) {

      ptr = (char *)&szTitle[y][0];

      PCMidFont(ptr, XMOS, y1, 1, drawcolor, outlinecolor);

      y1+=CELL_SIZE;

    }

    PCMidFont(ptr, XMOS, y1, 1, drawcolor, outlinecolor);

    PCMidFont(ptr, XMOS, y1+CELL_SIZE, 1, drawcolor, outlinecolor);

 

    // a little finishing touch for the help screen

    // to show the currently selected colors.

    xx = XMOS-136;

    c = 1;

      PCMidFont("C", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("u", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("r", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("r", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("e", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("n", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("t", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont(" ", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("C", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("o", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("l", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("o", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("r", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont("s", (xx+=8), y1, 1, (c++), drawcolor);

      PCMidFont(":", (xx+=8), y1, 1,  c,    drawcolor);

      PCMidFont(" ", (xx+=8), y1, 1,  c,    drawcolor);

    c = 0;

    PCMidFont("0", (xx+=8), y1, 1, (c++), outlinecolor);

    PCMidFont("1", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("2", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("3", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("4", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("5", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("6", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("7", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("8", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("9", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("A", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("B", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("C", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("D", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("E", (xx+=8), y1, 1, (c++), drawcolor);

    PCMidFont("F", (xx+=8), y1, 1,  c,    drawcolor);

    y1+=CELL_SIZE;

    y1+=CELL_SIZE;

 

    x1 = strlen(ptr) * 4;

    LineBox(XMOS - x1 + 2, yorg+1, XMOS + x1 - 1, y1-2, drawcolor);

 

    EatKeys();

    while (!kbhit());

    EatKeys();

 

}

 

void main(int argc, char **argv)

{

  int status = 0, idx, iMax, dhrscale = 2;

 

  /* bounds of hires image */

  int oldx1=20, oldy1=4, oldx2=299, oldy2=195;

  int x1=20, y1=4, x2=299, y2=195;

 

  uchar c, kdx;

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

  uchar *wordptr;

  uchar scratchbuf[128];

  FILE *fp;

 

  if(argc == 1) {

    puts(szTextTitle);

    puts("Command line Usage is \"BMPA2FC MyCGA.PCX\"");

    puts("                      \"BMPA2FC MyBSAVE.BAS\"");

    puts("                      \"BMPA2FC My16Color.BMP\"");

    puts("                      \"BMPA2FC My24BitPalette.BMP\"");

    puts("                      \"BMPA2FC MyCGA.PCX OutfileBaseName\"");

    puts("                      \"BMPA2FC MyBSAVE.BAS OutfileBaseName\"");

    puts("                      \"BMPA2FC My16Color.BMP OutfileBaseName\"");

    puts("                      \"BMPA2FC My24BitPalette.BMP OutfileBaseName\"");

 

    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;

  }

 

  if((rawbuffer = malloc((unsigned)65000)) == NULL) {

    puts(szTextTitle);

    puts("Out of Memory...");

    exit(1);

  }

 

 

  strcpy(sname, fname);

  wordptr = strtok(sname, ".");

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

 

  status = PCX_Read(sname);

  if(status)status = BSAVE_Read(sname);

  if(status)status = BMP16_Read(sname);

  if(status)status = BMP24_Read(sname);

  if (status) {

    puts(szTextTitle);

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

    free(rawbuffer);

    exit(1);

  }

 

  status = ESCKEY;

 

  if((SetCrtMode(MCGA)) == MCGA) {

    SetPalette();

    LoadPalette();

    vload();

    ShowTitle();

    vload();

    xbox(oldx1, oldy1, oldx2, oldy2);

    do {

      c=toupper(getch());

 

      if (FUNCKEY == c) {

        kdx=getch();

        switch(kdx) {

              case HOMEKEY:

                   x1 = 0;

              case LTARROW:

                   x1-=1;

                   x2-=1;

                   if (x1 < 0) {

                         x1 = 0;

                         if (dhrscale == 1) x2 = 139;

                         else x2 = 279;

                   }

                   break;

          case ENDKEY:

               x2=319;

          case RTARROW:

                   x1+=4;

                   x2+=4;

                   if (x2 > 319) {

                         x2 = 319;

                         if (dhrscale == 1)x1 = 319 - 139;

                         else x1 = 319 - 279;

                   }

                   break;

          case PGUP:

               y1 = 0;

          case UPARROW:

                   y1-=1;

                   y2-=1;

                   if (y1 < 0) {

                         y1 = 0;

                         if (dhrscale == 1)y2 = 95;

                         else y2 = 191;

                   }

                   break;

          case PGDOWN:

               y2 = 199;

          case DOWNARROW:

                   y1+=4;

                   y2+=4;

               if (y2 > 199) {

                        y2 = 199;

                        if (dhrscale == 1)y1 = 199 - 95;

                        else y1 = 199 - 191;

                     }

 

                   break;

          default:

            break;

        }

      }

      else {

 

        if (c == 'S' || c == ENTERKEY)

          break;

 

        switch (c) {

                  // scaling feature

              case 'X':

                xbox(oldx1, oldy1, oldx2, oldy2);

                if (dhrscale == 1)

                        dhrscale = 2;

                  else

                      dhrscale = 1;

 

                  x2 = x1 + (140 * dhrscale)-1;

                  y2 = y1 + (96 * dhrscale)-1;

                if (x2 > 319) {

                        x2 = 319;

                        if (dhrscale == 1)x1 = 319 - 139;

                        else x1 = 319 - 279;

                  }

            if (y2 > 199) {

                        y2 = 199;

                      if (dhrscale == 1)y1 = 199 - 95;

                      else y1 = 199 - 191;

                  }

                  oldx1 = x1; oldx2 = x2;

                  oldy1 = y1; oldy2 = y2;

                  xbox(oldx1, oldy1, oldx2, oldy2);

                  break;

 

          case 'H':

            xbox(oldx1, oldy1, oldx2, oldy2);

            ShowTitle();

            vload();

            xbox(oldx1, oldy1, oldx2, oldy2);

            break;

          case 'Q':

            c = ESCKEY;

            break;

          default:

            if (c < '0' || c > 'F') break;

            if (c > '9' && c < 'A') break;

            TogglePalette(c);

        }

      }

 

      if (x1!=oldx1 || y1!=oldy1) {

           /* erase old box */

           xbox(oldx1, oldy1, oldx2, oldy2);

           /* update old cords with new cords */

           oldx1 = x1; oldy1 = y1; oldx2 = x2; oldy2 = y2;

           /* plot new box */

           xbox(oldx1, oldy1, oldx2, oldy2);

        }

 

 

    } while (c!=ESCKEY);

 

    if(c!=ESCKEY)

      status = savedhrfragment(outfile,x1,y1,dhrscale);

    else

      status = ESCKEY;

 

    SetCrtMode(TEXT);

 

  }

 

  if (status != ESCKEY) {

    if (status == SUCCESS)printf("%s.AUX & .BIN and %s.2FC Saved!\n",outfile,outfile);

    else printf("Error saving %s.AUX & .BIN and %s.2FC!\n",outfile,outfile);

  }

  else printf("Exiting without saving...\n");

 

  free(rawbuffer);

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

  exit(0);

 

}