/* ------------------------------------------------------------------------ */
/* 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, ®s, ®s, &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);
}