In the Lisa Hardware Manual, it says that expansion card icons can be stored in a compressed format if the MSB of the icon count byte is set. And it also states that "a special program is currently available to do the compression", but I'm guessing that program has probably been lost to time. Does anybody know how this compression algorithm works and how the compressed icons are stored? After compression, are all icons the same length in ROM or or does the length of the icon vary based on the efficiency of the compression on that particular icon?
A snippet from Chuck Lukaszewski (author of MW+) says:
* the unpacking routine gets a byte of 8 flags */
* shifts flags right 1 bit, if the carry is set, clears a byte on the screen */
* if the carry is clear, copies the next byte to the screen */
* after doing all 128 screen bytes, the routine takes the top line */
* and XORs it with the line below it, then takes that line and XORs it */
* with the one below and so on to the bottom */
In the "Apple Lisa Boot ROM Listing.pdf" the unpack routine DSPICON is at 0x35E2
In the source file "Lisa Graphics RM248.G.TEXT" :
;---------------------------------------------------------------------
;
; Routine to display compressed icon.
;
; INPUTS:
; A2 = pointer to compressed icon
; A6 = pointer to (even!) screen address for upper left hand
; corner of icon
; SIDE EFFECTS:
; A6 is trashed
;---------------------------------------------------------------------
DSPICON
MOVEM.L D0-D2/A0/A2,-(SP) ; CHG009
MOVE.L A6,A0 ; save screen start address
MOVEQ #23,D1 ; There are 24 octals in an icon
MOVEQ #5,D2 ; reset row bytes counter
DLOOP MOVE #$100,D0 ; prime D0 for 8 bit count count
MOVE.B (A2)+,D0 ; load map byte from compressed image
MLOOP LSR.W #1,D0 ; shift off map bit
BEQ.S DONE ; byte done when = 0
BCC.S BLACK ; dispatch on the bit
CLR.B (A6)+ ; store zero in new
BRA.S CHECK ; continue for all 8 bits
BLACK MOVE.B (A2)+,(A6)+ ; store byte in new
CHECK DBF D2,MLOOP ; see if on scanline seam(every 6 bytes)
ADDA #90-6,A6 ; bump to next scanline RM015
MOVEQ #5,D2 ; reset row bytes counter
BRA.S MLOOP ; continue for all 8 bits
DONE DBF D1,DLOOP ; do the rest of the octals in ICON
; Now unXOR the icon on the screen
MOVE.L A0,A6 ; get screen pointer saved above
MOVE.L A6,A2 ; second pointer
ADDA #90,A2 ; scanline pointer RM015
MOVE #30,D1 ; do 31 scanlines
; This is the cause of the even destination restriction
XLOOP MOVE.L (A6)+,D0 ; get long from previous scanline
EOR.L D0,(A2)+ ; xor into this scanline
MOVE.W (A6)+,D0 ; get word from previous scanline
EOR.W D0,(A2)+ ; xor into this scanline
ADDA #90-6,A2 ; next scan line + rowbytes RM015
ADDA #90-6,A6 ; next scan line + rowbytes RM015
DBF D1,XLOOP
MOVEM.L (SP)+,D0-D2/A0/A2 ; CHG009
RTS
The #90 constants are screen size dependent ( # horizontal pixels / 8 ) so would be different in the 3A ROM, but this doesn't affect the compression algorithm, only the code that draws into the screenbuffer.
I think the compression goes like this:
Starting with the final bitmap...
Step 1: Turn solid black blocks into zeros by using XOR to encode only the changes from row to row:
Start at the bottom (last) row, XOR with the (second last) row above it, to obtain the last row of the uncompressed data, XOR that with the (third last) row of original data to obtain the second last row of uncompressed data. Repeat until you reach the top row which is copied verbatim to the uncompressed data.
Step 2: Now the compression step will remove the zero bytes from the uncompressed data from step 1: prior to each run of
8 6 bytes in a row, a flag byte is added, where each flag bit corresponds to an image data byte in a row from step 1. If an image data byte is zero, the corresponding flag bit is set and that zero image data byte is removed (thus saving a byte).
Hence the compression effectiveness depends on the icon. If the icon is a checkerboard, the compression method actually increases the size because the flag bytes are added but there are no zero bytes to remove. If the icon is all white, all the data bytes are removed and only the flag bytes remain.
I once had a suspicion that the Macintosh used a similar icon compression method, but I don't recall if that was confirmed or not.
HTH, I apologize for my errors above, I hope they are easy to find.
edit: I now see that the code is for a 48 bit wide icon, so the rows are 6 bytes and so only 6 flag bits are used per row
edit2: it looks like the BEQ.S DONE branch in MLOOP might be to ... ummm changed my mind...