Re: Aztec C Text Colours - was Re: New C64 CC65 blog post
- From: "Bill Buckels" <bbuckels@xxxxxxx>
- Date: Mon, 31 Aug 2009 14:05:59 -0500
"Bill Buckels" <bbuckels@xxxxxxx> wrote:
I also provided screen designer utilities.
See bsv2x64.c for details
This runs from the Windows Command Line and comes with the compiler at:
http://www.aztecmuseum.ca
/* bsv2x64.c (C) Copyright Bill Buckels 2008 */
/*
converts IBM BSaved text screens like those created in TheDRAW to
Commodore 64 compatible BSaved text screens suitable for use as C64
program screens.
also produces a character array suitable for embedding in an Aztec C C64
application.
compiled under Microsoft (R) C/C++ Version 8.00c as a 16 bit MS-DOS
application. Should probably be ok for other compilers with minor
adjustments like headers and constants and storage considerations.
But since this is absolutely trivial compared to what is going on here
in an absolutely trivial application I have left this part as is
for readability purposes.
In this program I translate 144 IBM characters accurately to their
respective 128 commodore 64 equivalents. I will leave it to you to
decide for yourself how this is possible.
for more information on the bsaved text format see my wikipedia article
at:
http://en.wikipedia.org/wiki/BSAVE_(graphics_image_format)
*/
/*
C64 SCREEN MEMORY MAP
COLUMN 1063
0 10 20 30 39 /
+------------------------------------------------------------/
1024 | | 0
1064 | |
1104 | |
1144 | |
1184 | |
1224 | |
1264 | |
1304 | |
1344 | |
1384 | |
1424 | | 10
1464 | |
1504 | | ROW
1544 | |
1584 | |
1624 | |
1664 | |
1704 | |
1744 | |
1784 | |
1824 | | 20
1864 | |
1904 | |
1944 | |
1984 | | 24
+------------------------------------------------------------\
\
2023
The actual values to POKE into a color memory location to change a
character's color are:
0 BLACK 4 PURPLE 8 ORANGE 12 GRAY 2
1 WHITE 5 GREEN 9 BROWN 13 Light GREEN
2 RED 6 BLUE 10 Light RED 14 Light BLUE
3 CYAN 7 YELLOW 11 GRAY 1 15 GRAY 3
For example, to change the color of a character located at the upper
left-hand corner of the screen to red, type: POKE 55296,2.
C64 COLOR MEMORY MAP
COLUMN 55335
0 10 20 30 39 /
+------------------------------------------------------------/
55296| | 0
55336| |
55376| |
55416| |
55456| |
55496| |
55536| |
55576| |
55616| |
55656| |
55696| | 10
55736| |
55776| | ROW
55816| |
55856| |
55896| |
55936| |
55976| |
56016| |
56056| |
56096| | 20
56136| |
56176| |
56216| |
56256| | 24
+------------------------------------------------------------\
56295
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define SUCCESS 0
#define FAILURE 1
/* 16 color indices for the VIC II C64 */
enum { C64_BLACK=0,
C64_BWHITE,
C64_RED,
C64_CYAN,
C64_PURPLE,
C64_GREEN,
C64_BLUE,
C64_YELLOW,
C64_ORANGE,
C64_BROWN,
C64_LRED,
C64_DGRAY,
C64_MGRAY,
C64_LGREEN,
C64_LBLUE,
C64_LGRAY};
/* IBM 16 color remapping for C64 conversion using the IBM indices to
the C64 indices
C64_BROWN is never used (no IBM equivalent)
C64_DGRAY is never used (too dark)
C64_PURPLE is used for both MAGENTA and LMAGENTA
C64_CYAN is used for both CYAN and LCYAN
C64_LGRAY is used for WHITE
*/
unsigned char Vga2C64[16] = {
C64_BLACK,
C64_BLUE,
C64_GREEN,
C64_CYAN,
C64_RED,
C64_PURPLE,
C64_ORANGE,
C64_LGRAY,
C64_MGRAY,
C64_LBLUE,
C64_LGREEN,
C64_CYAN,
C64_LRED,
C64_PURPLE,
C64_YELLOW,
C64_BWHITE};
FILE *fp = NULL, *fp2 = NULL,*fp3 = NULL;
/* a microsoft compatible bsaved text image format descriptor */
unsigned char BSV_header[7]={
'\xfd', /* ID Flag = file descriptor identifier bsaved file */
'\x00', '\xb8', /* base address = LSB | MSB original segment */
'\x00', '\x00', /* offset from base = LSB | MSB original offset */
'\xA0', '\x0F' /* file size = LSB | MSB of bytes to be loaded + */
/* size of descriptors in bytes (8) */
};
/* buffers for the ibm character-attribute pairs */
unsigned char bsvbuffer[4000], ptxbuffer[4000];
/*
Remap ibm screen characters to commodore 64 screen character
equivalents. All IBM DOS OEM characters that do not have a PETSCII
equivalent are taken as spaces (32).
The following table translates IBM oem ASCII into commodore 64
shifted (mixed case) PETSCII for writing directly to the C64 screen in
standard text mode (not multicolor).
This means that you can only use one background color.
The mapping to do this is different from printing the same ascii values
since when printing ascii on the C64 many of the values are screen
control codes mixed-in with characters. The indices in the table below
cannot be used for printing. For example the C64 petscii value is 1 for
the lowercase 'a' when writing to screen memory.
By adding 128 to the values in the table, a reverse character is
displayed.
This means that the background color is used to print the text, and the
text color is used to print the background. In other words adding 128
to the translated table value reverses the video.
It can also be used to translate into unshifted petscii provided the
ascii value is converted tolower() before being used as an indices into
the table. Your choice, keeping in mind that the upper case only
translation of these will be displayed in lower case if mixed case
screen mode is used and the lower case version will display upper case
characters as "garbage" if vice versa.
Prior to loading these on the C64 the screen the first step would be
putchar(14) to switch to mixed case. or if upper case only to
putchar(142) then to clear the screen and home the cursor by
putchar(147).
All the Alpha-Numeric characters can be directly translated, and almost
all the punctuation characters can be directly translated with the
notable exceptions of a dos style slash, an opening single quote, an
underscore, and a caret. I am able to provide a C64 substitution for
the underscore, and subsitute the closed single quote for the open
single quote.
You'll have to do without the dos slash and the caret.
The standard IBM box drawing characters are translated as well. Keeping
in mind that both the IBM and commodore have their own unique graphics
characters, it is only the IBM box characters that can be translated to
a single line equivalent on the C64.
The commodore's block graphics are not the same as the IBM's and a
right half and top half are not available on the C64, so I substitute a
right third and top third. A left half and bottom half are available but
if all are to be used together to create a block-pixel image a slight gap
will show rightwise and topwise which may degrade the result.
Stay away from block graphics if you can and stick to boxes and
standard characters if you are preparing screens for conversion to C64.
The idea here is not to translate all the ibm characters into commodore
64 characters but rather to provide a slightly compromised character set
mostly on the IBM hi-ascii side that will fit into the C64's standard
128 positions. 144 IBM characters are translated accurately in the
table with the exceptions that I have noted.
The scientific notation and multi-lingual characters from the IBM have
no PETSCII equivalent and are not translated. I was lazy when
translating the IBM multilingual characters allowing that it is better
for the user to make whatever substitution they wish from the upper
and lower case alphabets themselves. As an english speaking western
Canadian what I have done here suits my purposes just fine thanks.
If a commodore 64 equivalent is not possible a blank character is
printed.
Despite the caveats noted above, a thoughfully constructed 40 column x
25 row area saved as an 80 column x 25 row BSaved Text Screen with a
single background color (preferably black) will translate intact to a
commodore 64 equivalent, allowing you to use a utility like TheDraw on
the IBM to do your C64 screen layouts.
*/
/* if you have qedit or some other DOS editor with an oem ascii chart
you can refer to that and compare it to a petscii chart to see why
I have done what I did. Note that most if not all petscii charts
will give you the C64 screen control characters as well. this is
not the way the C64 works at the screen memory level although much
of the ordering is the same. If you fail to see the corelation
then trust me on this one... the values below are correct.
The key to the table below is to remember that the "at" sign is at
subscript zero, followed by the lowercase 'a' to 'z' hence the
numbers 1-26 at the IBM position for these.
The next key to the table is to remember that beginning at position
32 the IBM values and commodore values are exactly the same right
through to 'Z' with the exception of the "at" sign as noted above.
The third key to the table is to remember that the high ascii
box drawing characters on the IBM (you can see these clustered
towards the end of the array below) map to common values on the
C64 whether you use the mixed-case or the upper-case character
set on the C64. You can also see the IBM pound (currency) sign
hanging-out by itself.
You will also note that if I had translated the non-english IBM
characters into my choice for mapping the english alphabet the
table would not be as clear to read nor for me to construct
since it is hand-built. Hence, I am adamantly lazy prefering
readability over busy-work.
If you want more detail study this a little closer. If you
want multi-lingual characters to map to english characters
add them yourself.
The C64 provides for custom fontsets to be used to solve that
problem which we will get to in a different sample program
than this one. When you use a custom fontset on the C64 even
your keys remap, so you'd better get that one right for the
country and keyboard you're programming for.
'nuff said.
*/
unsigned char ibm2petscii[256] = {
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
30, ' ', 31, ' ', ' ', ' ', ' ', ' ',
' ', '!', 34, '#', '$', 37, '&', 39,
'(', ')', '*', '+', ',', '-', '.', 47,
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 27, ' ', 29, ' ', 111,
39, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, '(', 93, ')', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', 28, ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
102, 102, 102, 93, 115, 115, 115, 110,
110, 115, 93, 110, 125, 125, 125, 110,
109, 113, 114, 235, 64, 91, 235, 235,
109, 112, 113, 114, 235, 64, 91, 113,
113, 114, 114, 109, 109, 112, 112, 91,
91, 125, 112, 102, 98, 97, 118, 120,
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
/* derivative background color count */
int bgcnt[16];
/* file and output names */
char c64array[128];
char c64screen[128];
char c64colors[128];
char arrayname[128];
char ErrorMessage[128];
int bsv2x64(char *bsvname)
{
FILE *bsvfile;
unsigned char *ptr, a, c, ch, fg, bg;
unsigned idx, jdx, row, cnt, adder;
unsigned char background,color;
// PTX support added to ClipShop
// also added here for the funnery of it
int bPTX = FALSE;
unsigned int byteoff=0,secondoff=1,packet;
unsigned char byte,bytecount;
int wordcount,target;
/* use pessimistic approach for error */
sprintf(ErrorMessage,"Can't open %s",bsvname);
if((bsvfile=fopen(bsvname,"rb"))==NULL)return FAILURE;
sprintf(ErrorMessage,"%s is an unrecognized format.",bsvname);
/* be optimistic that file is supported */
strcpy(arrayname, bsvname);
jdx = 999;
for (idx = 0; arrayname[idx] != 0; idx++) {
c= tolower(arrayname[idx]);
arrayname[idx] = c;
if (c=='.')jdx = idx;
}
if (jdx != 999)arrayname[jdx] = 0;
strcpy(c64array,arrayname);
strcpy(c64screen,arrayname);
strcpy(c64colors,arrayname);
strcat(c64array,".h");
strcat(c64screen,".bxd"); /* screen data */
strcat(c64colors,".bxc"); /* screen colors */
fread(ptxbuffer,7,1,bsvfile);
for(idx=0;idx<5;idx++)
{
if(ptxbuffer[idx]!=BSV_header[idx])
{
rewind(bsvfile);
fread(ptxbuffer,128,1,bsvfile);
if (ptxbuffer[0]==0 && ptxbuffer[1]==3 &&
ptxbuffer[2]==1 && ptxbuffer[3]==16) {
bPTX = TRUE;
break;
}
fclose(bsvfile);
return FAILURE;
}
}
/* support for PTX files
these use the ZSoft PCX run length encoding
and encode the characters first and the attributes
second which provides for good compression
on most text screens */
if (bPTX == TRUE) {
target = fread(ptxbuffer,1,4000,bsvfile);
wordcount=0;
do{ bytecount=1; /* start with a seed count */
byte=ptxbuffer[wordcount];
wordcount++;
/* check to see if its raw */
/* if its not, run encoded */
if(0xC0 == (0xC0 &byte)){
bytecount= 0x3f &byte;
byte=ptxbuffer[wordcount];
wordcount++;
}
for(packet=0;packet<bytecount;packet++){
if(byteoff<4000){
bsvbuffer[byteoff]=byte;
byteoff+=2;
}
else{
if (secondoff<4000) {
bsvbuffer[secondoff]=byte;
secondoff+=2;
}
}
}
}while(wordcount<target);
}
else {
fread((char *)&bsvbuffer[0],4000,1,bsvfile);
}
fclose(bsvfile);
strcpy(ErrorMessage,"Unable to open output file(s).");
/* remember to rename these to lowercase
if using c1541 to create disk images.
if we had compiled this as a 32 bit application
XP would have done that for us since I use lowercase
output filenames. */
fp = fopen(c64array,"w");
fp2 = fopen(c64screen,"wb");
fp3 = fopen(c64colors,"wb");
if (NULL == fp || NULL == fp2 || NULL == fp3) {
if(NULL != fp)fclose(fp);
if(NULL != fp2)fclose(fp2);
if(NULL != fp3)fclose(fp3);
return FAILURE;
}
sprintf(ErrorMessage, "Output files %s[.h, .bxd, .bxc] created!",
arrayname); /* good enough */
/* set count to zero */
for (idx = 0; idx < 16; idx++)bgcnt[idx] = 0;
/* loop 25 rows - one for each character line in the text screen */
/* first we do a background color prevalence test */
/* generally what we want is a screen that has been prepared
with primarily a black background */
for(row=0;row<25;row++)
{
/* offset 80 - columns each row */
ptr = (unsigned char *)&bsvbuffer[row*160];
for(jdx=0;jdx<40;jdx++)
{
c=*ptr++; /* character */
a=*ptr++; /* attribute pair */
/* fg = (a&0x0f);*/
bg = (a>>4);
bgcnt[bg]+=1;
}
}
/* we need to establish a global background */
/* the test below will determine the most prevalent */
/* background in the source image and use it */
cnt = bgcnt[0];
background = 0;
for (idx = 1; idx < 16; idx++) {
if (bgcnt[idx] > cnt) {
background = idx;
cnt = bgcnt[idx];
}
}
fprintf(fp,"/* character array created from IBM text screen %s */\n",
bsvname);
fprintf(fp,"/* array structure is C64 screen value, C64 color value
*/\n");
fprintf(fp,"char %s[2000] = {\n",arrayname);
/* load screen to default address of 1024 */
/* screen datafile size is 1000 bytes */
/* screen colorfile size is 1000 bytes */
/* C64 bsaved headers with load address */
/* you should be able to bload these in basic 7
on a c128 although I haven't tried it.
basic 2 doesn't have a bload and you will need
to test these from the command line using the
load binary command on a c64.
in aztec C we have the bload command available
(I have written a system level load but not run)
or we can just read the thing from disk, or embed
it as an array. Aztec C Rules!
*/
fputc(0,fp2);
fputc(4,fp2); /* 0x400 */
fputc(0,fp3);
fputc(0xd8,fp3); /* 0xd800 */
cnt = 0;
for(row=0;row<25;row++)
{
/* offset 80 - columns each row */
/* but we will only use 40 of them */
ptr = (unsigned char *)&bsvbuffer[row*160];
for(jdx=0;jdx<40;jdx++)
{
c=*ptr++; /* character */
a=*ptr++; /* attribute pair */
fg = (a&0x0f);
bg = (a>>4);
adder = 0;
/* if the foreground matches the global background
swap-in the color and reverse the character.
this will give us the proper value for the
the ibm color that is being used for the real background
color.. for example if the global background is black
and black text is printed on a CYAN background...
otherwise plot the text color on the global background */
if (fg == background) {
adder = 128; /* reverse character */
fg = bg;
}
color = Vga2C64[fg];
ch = ibm2petscii[c] + adder;
fputc(ch, fp2); /* screen */
fputc(color,fp3); /* color */
fprintf(fp," %3d, %3d", ch, color);
cnt += 1;
if (cnt == 8) {
/* newline every 8 pairs */
/* terminate the array properly */
if (row == 24 && jdx == 39) fprintf(fp,"};\n");
else fprintf(fp,",\n");
cnt = 0;
}
else {
fprintf(fp,",");
}
}
}
fclose(fp);
fclose(fp2);
fclose(fp3);
return SUCCESS;
}
void main(int argc, char *argv[])
{
int xfile = 2;
if(argc!=2)
{
puts("Usage is \"bsv2x64 my.bsv\"");
puts("BSV or PTX filename required...");
}
else {
if ((xfile = bsv2x64(argv[1]))!= SUCCESS)
printf("OOPS! %s\n",ErrorMessage);
else
puts(ErrorMessage);
}
exit(xfile);
}
.
- References:
- New C64 CC65 blog post
- From: Jim Lawless
- Aztec C Text Colours - was Re: New C64 CC65 blog post
- From: Bill Buckels
- New C64 CC65 blog post
- Prev by Date: Re: Replace C64 kernal with cartridge..
- Next by Date: Re: So very sad
- Previous by thread: Aztec C Text Colours - was Re: New C64 CC65 blog post
- Next by thread: Commodore 64 Arcade Machine - uIEC - Wireless Internet
- Index(es):
Relevant Pages
|
Loading