; file 4bit2fli.s
;
; converts 4bit format to FLI format
; By Todd S. Elliott - after heavy adaption of Arndt's svr.FlipRaw routines
; used in his GoDot program. By courtesy of Arndt Dettke.
; Make sure the makec64 routine has been called already.
; Make sure that valid 4bit data has been loaded to $4000 of the first
; available bank of SuperRAM (normally $02).
; After finishing, the FLIP raw data file will be at $3c00-7fff for further
; massaging.
; some equates, etc.
colorram   = $0a	; pointer for the color info of picture data in Color RAM
pixeldat   = $0c	; pointer for the pixel data of picture in hi-res screen
videoram   = $0e	; pointer for the color info of picture data in Video Matrix
fourbit'data = $15	; word pointer to four bit data
optcolor   = $2f	; optimized color for color memory
colorcount = $30	; color count registers (16 bytes)
histogram  = $40	; distribution of color in a card or single row
histotab   = $50	; bit patterns corresponding to the color histogram
sb         = $89	; start bank of exp. RAM
xtemp      = $8c	; .X register temporary location
ytemp      = $8d	; .Y register temporary location
temp       = $8e	; temporary two-byte zero page location for variable storage
zp         = $fb	; zero page variable for various purposes
c64   	   = $3b00	; buffer for converting the GoDot palette to 64 palette
cram       = $3c00	; color ram table containing GoDot palette
gdata      = $4000	; 4 bit buffer for GoDot data files
convert'4bit =*
; set up tables first
    jsr setables
cloop =*
    lda sb		; get bank - normally $02
    pha
    .byte $ab		; PLB - set bank
    lda #$08		; do 8 cardrows at a time to finish a single graphics card
    sta zp+2
    ldx #$1f		; clear out the color distribution table
s8  lda #$00		; including colorcount and histogram (.X = $1f)
-   sta colorcount,x	; colorcount is a zero page location
    dex
    bpl -
    ldy #$03		; do a cardrow at a time (4 bytes of 4bit data)
-   lda (fourbit'data),y; get 4bit data
s2  and #%00001111	; get rid of upper nybble
    nop
    nop			; self-modifying code used here - use LSR to get rid of lower nybble
     			; A graphics cardrow of 4bit data contains eight values, where each
     			; value occupies a nybble for a total of four bytes. In the future,
     			; I will allow the user to select either left or right nybbles from
     			; the 4bit data. As it stands now, only the right nybbles are
     			; extracted from the 4bit data.
    tax			; index the byte found there
    inc colorcount,x	; and count the colors found so far
    dey
    bpl -		; go through a single cardrow
    iny			; optimize a single color for colorram
    sty colorcount	; zero out the index
    ldx #$0f
-   lda colorcount,x
    beq +		; if empty color then skip count
    iny			; need to know how many individual colors were detected
+   dex			; go through all available c64 colors
    bpl -
    cpy #$03		; at least 3 different colors were detected on a single cardrow?
    bcc +		; if not, then do not include detected colors onto the histogram
       			; The idea is to create a histogram containing only color counts
       			; from individual graphic cardrows having 3 or more different colors.
       			; If an individual graphic cardrow only has 1 or 2 different colors,
       			; then they can be included in the video matrix information. This
       			; way, the selection routines optimizes the best color for that
       			; graphics card (8 graphic cardrows) in its COLOR RAM counterpart.
    ldy #$03		; do a cardrow at a time (4 bytes of 4bit data)
-   lda (fourbit'data),y; get 4bit data
s7  and #%00001111	; get rid of upper nybble
    nop
    nop			; self-modifying code used here - use LSR to get rid of lower nybble
    tax			; index the byte found there
    inc histogram,x	; and count the colors found so far
    dey            	; histogram is also a zero page location
    bpl -		; go through a single cardrow
+   clc
    lda fourbit'data	; increment the source address
    adc #$04		; to advance to the next cardrow (each graphics cardrow contains
    sta fourbit'data	; four bytes of 4bit data.)
    bcc +
    inc fourbit'data+1	; ditto high byte
+   ldx #$0f		; for the colorcount clear
    dec zp+2		; are we done with a single graphics card?
    bne s8  		; a single graphics card contains 8 graphics cardrows
; if the routine below had a .X =1 and went up to 15 instead of the other way
; around, the colors selected could be slightly different.
; According to GoDot's brightness palette, this routine is designed to select
; brighter colors for the color ram.
    ldy #$00
    sty optcolor	; default color is black (optcolor is a zero page location.)
    sty histogram	; and zero out the black color entry
    ldx #$0f		; go through the histogram
-   lda histogram,x
    beq +		; if empty then skip that color
    cmp histogram	; compare the count against the most counted color
    beq +		; if equal then skip that color
    bcc +		; if less then skip that color
    sta histogram	; if more then make it the new 'most counted' color
    stx optcolor	; and store the corresponding color entry here
+   dex
    bne -		; go through colors $01-$0f
    .byte $da		; PHX
    .byte $ab		; PLB - set bank to zero
    lda optcolor	; place the optimized color into corresponding colorram
    .byte $92,$0a	; sta (colorram)
    .byte $c2,$20	; REP #$20 - turn on 16 bit memory accesses and .A
    inc colorram	; increment colorram offset
    dec zp		; are we done with 1000 graphics cards?
    .byte $e2,$20	; SEP #$20 - turn on 8 bit mode
    beq +
    jmp cloop		; otherwise, go back and repeat
; set the tables again
+   jsr setables
s4  lda #$08		; do 8 card rows for a single graphics card
    sta zp+2
    lda #$00
    sta zp+3		; hi byte set to zero
s9  ldx #$0f
    lda #$00
-   sta colorcount,x	; clear out color counts
    dex
    bpl -
    ldy #$03		; get a cardrow of 4 bit data
-   lda sb		; normally $02 for bank activities
    pha
    .byte $ab		; PLB
    lda (fourbit'data),y
s3  and #%00001111
    nop
    nop			; self modifying code used here -   use LSR instead for upper nybble
    tax
    lda #$00		; $00 for bank activities
    pha
    .byte $ab		; PLB
    inc colorcount,x	; count colors
    lda bits,y
    sta bitpatt,y	; create a bit pattern table
    lda #32		; clear the color table as well
    sta coltable+1,y
    dey
    bpl -
    iny
    sty colorcount	; clear out the black color entry
    sty coltable	; and ditto for the background color entry
    lda (colorram),y	; check its corresponding color ram value
    beq +		; if zero then skip
    tax			; assign the colorram value into the color table
    tya
    sta colorcount,x	; and zero out the corresponding color entry
                  	; Since the current graphics cardrow already has a
                  	; corresponding color ram entry for its entire graphics
                  	; card, do not include it in the color counting routines.
    stx coltable+3	; it is the color ram's color entry
; If .X = $01 and went up to $0f, the colors selected below could be slightly
; different. As it stands now, the colors selected tend to be brighter
; according to the brightness of GoDot's color palette
+   ldx #$0f		; find most used color in a single cardrow
-   lda colorcount,x
    beq +		; if empty, move onto the next color entry
    cmp colorcount	; check for the highest number of a single color
    beq +		; if equal numbers then skip that color entry
    bcc +		; if less numbers then obviously skip that color entry
    sta colorcount	; make it the new number showing highest count of a color
    stx coltable+1	; and the color entry into the color table
+   dex			; for videoram (upper nybble).
    bne -
    lda coltable+1
    cmp #32		; has it been filled in by a color entry?
    beq ++		; if not, skip the second color check
    tax     		; the videoram matrix can accept two different colors, one for
    tya     		; each nybble
    sta colorcount,x	; clear out the color entry that was previously found
                  	; we wouldn't want it to show up in the other nybble.
    sta colorcount	; and start the search for a second color
    ldx #$0f		; find second most used color in a single cardrow
-   lda colorcount,x
    beq +		; if empty, move onto the next color entry
    cmp colorcount	; check for the highest number of a single color
    beq +		; if equal numbers then skip that color entry
    bcc +		; if less numbers then obviously skip that color entry
    sta colorcount	; make it the new number showing highest count of a color
    stx coltable+2	; and the color entry into the color table
+   dex			; for videoram (lower nybble).
    bne -
; at this point, the color table is now filled out.
; we need to insert color values into videoram matrix
+   lda coltable+2	; get selected videoram values
    and #$0f		; get rid of upper nybble
    sta temp		; save it temporarily - temp is a zero page location
    lda coltable+1
    asl			; move it to the upper nybble
    asl
    asl
    asl
    ora temp		; and add in the lower nybble
    sta (videoram),y	; both nybbles are added together and stashed into
                  	; the videoram matrix
; we need to sort the filled out color table with lower values first in
; an ascending order.
    ldx #$00
-   stx ytemp		; zero page location
    ldy #$03
-   lda coltable,x
    cmp coltable,y	; see which color entry is higher
    bcc +
    beq +		; if equal or less then do nothing
    pha
    lda coltable,y
    sta coltable,x	; otherwise, switch colors
    pla
    sta coltable,y
    lda bitpatt,x	; rearrange the corresponding bit patterns
    pha
    lda bitpatt,y
    sta bitpatt,x	; switch bitpatterns
    pla
    sta bitpatt,y
+   dey
    cpy ytemp		; go through all possible combinations to sort the color table
    bne -
    inx
    cpx #$03		; are we done sorting the color table?
    bne --
; next we need to spread out the colors onto a histogram
; this way, colors that have to be discarded due to the VIC's color
; limitations will be assigned to their neighboring colors on
; GoDot's brightness scale.
    ldy #$ff
    sty ytemp
-   iny
    lda coltable,y	; need to compute average of neighboring colors
    clc
    adc coltable+1,y
    lsr			; average the added colors
    cmp #16		; have we exceeded the maximum range?
    bcc +		; if so, then set .A to 15
    lda #15
+   sta xtemp
    lda bitpatt,y	; store in the bit pattern
    ldx ytemp
-   inx
    sta histotab,x	; create a histogram table of bit patterns
                  	; histotab is a zero page location
    cpx xtemp		; are we done creating a particular bit pattern on the histogram?
           		; xtemp is a zero page location
    bcc -
    cpx #15		; are we done with the entire histogram?
    bcs +		; branch out when done
    stx ytemp
    cpy #$03		; are we done with the sorted color table?
    bne --
; the bit patterns corresponding to their color values have been spread out
; over the histogram at histotab and can now be used to render the actual
; bitmap.
+   lda #$00
    sta temp
    ldy #$03
-   lda sb		; $02 -   set source bank
    pha
    .byte $ab		; PLB
    lda (fourbit'data),y; get GoDot's four bit values
s5  and #%00001111	; get rid of upper nybble
    nop
    nop			; self modifying code -   use LSR's here to get upper nybble
    tax			; index the color found
    lda #$00		; set bank to $00
    pha
    .byte $ab		; PLB
    lda histotab,x	; get the proper bit pattern
    and mask,y		; and set up the proper mask for inserting the proper bitpair
    ora temp		; we are creating four bitpairs onto the same byte
    sta temp
    dey
    bpl -
    lda temp		; has the byte containing graphics bitmap data
    iny
    sta (pixeldat),y	; and store it into the bitmap
    .byte $c2,$20	; REP #$20; turn on 16 bit memory accesses and .A
    clc
    lda fourbit'data	; get the next 4bit datastream
    .byte $69,$04,$00	; ADC #$0004
    sta fourbit'data
    clc			; is this opcode necessary?
    lda videoram	; increment videoram offset by 1Kb
    .byte $69,$00,$04	; ADC #$0400
    sta videoram
    inc pixeldat	; increment the pixel bitmap offset
    dec zp+2		; are we done with all 8 scanlines of a single graphics card?
    beq +
    .byte $e2,$20	; SEP #$20 -   turn on 8 bit mode
    jmp s9		; and repeat through a single graphics card
+   sec
    lda videoram	; decrement videoram offset by $1fff
    .byte $e9,$ff,$1f	; SBC #$1fff
    sta videoram
    inc colorram	; increment color ram offset
    dec zp		; and are we done with all 1000 graphics cards?
    .byte $e2,$20	; SEP #$20 -   turn on 8 bit mode
    beq +
    jmp s4		; otherwise, go back and repeat
; convert GoDot palette to 64 color palette
+   lda #$00
    .byte $eb		; XBA
    .byte $c2,$10	; REP #$10 turn on 16 bit registers
    .byte $a2,$ff,$23	; ldx #$23ff
-   lda cram,x		; get individual GoDot data in buffer
    tay			; index it
    lda c64,y		; and retrieve the color 64 equivalent
    sta cram,x		; and stash it onto video ram matrixes
    dex
    bpl -
    .byte $e2,$10	; SEP #$10 turn on 8 bit registers
    rts			; to exit the conversion routine
makec64 =*		; creates a table for converting the brightness palette of GoDot
          		; to the standard CBM color palette
    ldy #$00
-   tya
    lsr
    lsr
    lsr
    lsr
    tax
    lda cols64,x
    and #$f0
    sta zp
    tya
    and #$0f
    tax
    lda cols64,x
    and #$0f
    ora zp
    sta c64,y
    iny
    bne -
    rts
setables =*
; all locations are zero page
    lda #$00		; low byte
    sta fourbit'data
    sta videoram
    sta colorram
    sta pixeldat
    lda #>gdata
    sta fourbit'data+1	; location of 4bit data
    sta videoram+1
    lda #>cram
    sta colorram+1	; location of color ram containing GoDot palette
    lda #$60
    sta pixeldat+1	; location of pixel data at $6000
    lda #$e8
    sta zp
    lda #$03		; do this routine 1,000 times
    sta zp+1
    rts
; Table to convert GoDot palette to C64 palette
cols64 =*
    .byte $00,$66,$99,$bb,$22,$44,$88,$cc
    .byte $ee,$aa,$55,$ff,$33,$77,$dd,$11
bits =*			; bit patterns
    .byte $00,$55,$aa,$ff; %00, %01, %10, %11
mask =*			; the mask byte
    .byte $c0,$30,$0c,$03; %11000000, %00110000, %00001100, %00000011
coltable =*		; color table for a single cardrow of GoDot data
    .byte $00,$00,$00,$00,$00
bitpatt =*		; table of corresponding bitpatterns
    .byte $00,$00,$00,$00
; end file 4bit2fli.s