Here are some notes and pseudocode for implementing a 73 column x 4 row display. You could improve this to 73x16 rows on an expanded VIC, but this restricted 73x4 display leaves me with a comfortable amount of RAM on an unexpanded VIC (all I have).
Two screens are at 6144 and 6656. Font is at 7168 for 128 custom chars and 128 standard chars. Flipping between the two screens at 60fps allows for subpixel rendering, tricolor, and hybrid modes.
This 73 column demo will use overlapping bitmaps of 21x3 characters, consuming 126 of the 128 available custom chars. The subpixel rendering technique provides a resolution of 21*14x3*8, or 294x24 pixels. Each letter takes up 4x6 pixels, so we have a 73 column by 4 row display.
To minimize the font memory usage, and to simplify things, each glyph is packed into 2 bytes. These 16 bits provide a 3x5 bitmap plus a "shift bit". The "shift bit" signifies shifting the bitmap down, for descender characters (gjpqy). Thus, the 128 character font only consumes 256 bytes.
Code: Select all
Font encoding takes two bytes: FEDCBA98 76543210
F = shift bit (lowers font by one pixel)
E94
D83
C72
B61
A50
The character is rendered in 3 passes--one for each vertical line of pixels. First, bit twiddling is used to reorganize the data into a single byte:
This encoding is used so the byte may be simply ROL'd for each step. The current pixel is tested for via the high bit, and the loop is complete if the byte is zero.
After unpacking the current line of pixels, the starting address and bitmask are calculated. The first step is to divide the x coordinate by 14, leaving the remainder in A. However, to prevent overflow you divide by 7 instead:
Code: Select all
A = 2*column + [0/0/1] {half of the x coordinate}
X = -1
LOOP: {this loop divides A by 7}
A = A - 7
X = X + 1
repeat LOOP if A>0
A = A + 7 {undo overshoot}
A = 2*A + [0/1/0]
The next step is to calculate the starting address and bitmask:
Code: Select all
ADDR = 7*1024+6*row+24*X + [0/256/0]
MASK = LOOKUP_TABLE[A]
For example, the lookup table for green is:
Code: Select all
0 -> 128 01234567ABCD
1 -> 192
2 -> 64
3 -> 32
4 -> 32
5 -> 16
6 -> 16
7 -> 8
8 -> 12
9 -> 4
A -> 2
B -> 2
C -> 1
D -> 1
Note that this table is inverted from the above example, since the x coordinate is from left-to-right.
Next the current stripe is unpacked into a single byte bitmask via bit twiddling, taking into account the SHIFT bit:
This encoding is used so the current pixel can be tested via the high bit. This byte is ROL'd each step.
The address alternates between ADDR+X and ADDR+32*8+X; this assumes the bitmaps are organized so chars 0-31 are used for one field while chars 32-63 are used for the other field. Thus, incrementing the address involves incrementing X and XORing ADDR's high byte with 1. Thus, the basic loop steps are:
Code: Select all
Test high bit
if false then POKE ADDR+X, PEEK(ADDR+X) AND (255-MASK)
if true then POKE ADDR+X, PEEK(ADDR+X) OR MASK
X = X + 1
ADDR = ADDR XOR 32*8
This loop cycles 6 times for each vertical stripe; there are 3 vertical stripes.
I don't know if these ideas are at all comprehensible to anyone else. I'm working on a prototype in BASIC which will be SSSSLLLLLOOOOWWWWW, but should demonstrate the principle. The above thoughts are oriented toward machine code, though.