P286
; Code to view an Apple //GS 320x200x256 picture ($C1)
; Format is as follows:
; $0000-$7CFF   Picture data, in nibbles. Each nibble has the value of
;               1-16, specifying a color in the palette assigned to that
;               line.
; $7D00-$7DC7   Scanline Control Bytes. There are 200 of these, one for
;               each scanline. They are byte values, and break down like this:
;               Bits 0-3: Palette Number For Line (0-15)
;               Bit   4 : Reserved (must be 0)
;               Bit   5 : Fill Mode (0=off, 1=on)
;               Bit   6 : Scanline Interrupts for this line (0=off, 1=on)
;               Bit   7 : Graphics mode for this line (0=320, 1=640)
; $7DC8-$7DFF   Reserved - Filled with zeroes
; $7E00-$7FFF   Color Palettes 0-15. These are 16 colors, each represented
;               by words. They break down like so:
;               Bits 0-3  : Blue Intensity
;               Bits 4-7  : Green Intensity
;               Bits 8-11 : Red Intensity
;               Bits 12-15: Reserved (must be 0)
; 32767 Total Bytes
;
; LIMITATIONS: This code does not support the 640x200x256 GS picture mode,
;              because it sucks. Scanline interrupts were considered
;              irrelevant and are not implemented.
;
; Version 1.0 by Belgorath - (c) June 1993 DTCI / CyberCorps Labs
; Version 1.1 - Fixed 256-color implementation, added optimizations,
;               checking for errors on file open
; Version 1.2 - MUCH quicker color decoding / setting - Uses in, out
;               instead of int 10h. Also more optimizations
; Version 1.3 - Fill mode support added
; Comments to: belgo@gnu.ai.mit.edu

        DOSSEG
        MODEL   Small
        JUMPS
        STACK   400h
        .DATA
picdata db   7d00h dup(0)       ;Filler for picture data
scb     db   00c8h dup(0)       ;Filler for SCB's
shit    db   0038h dup(0)       ;Filler for zeroes
pals    db   0200h dup(0)       ;Filler for palette data
prmp    db   'Enter filename (.C1) to view > ',0
emsg    db   'Error Opening File!',0
fnam    db   255 dup (0) ;Filename for the $C1 picture

        .CODE

Start:
        mov     ax,seg prmp
        mov     ds,ax
        mov     dx,offset prmp
        call    puts_z
        mov     ax,seg fnam
        mov     ds,ax
        mov     dx,offset fnam
        mov     cx,250
        call    gets_z
        call    readit          ;Read in the file
        mov     ax,0013h
        int     10h             ;Set 320x200x256 MCGA Mode
        mov     ax,@data
        mov     ds,ax
        mov     si,offset picdata       ;DS:SI -> picture data
        mov     ax,0a000h
        mov     es,ax
        mov     di,00h          ;ES:DI -> VGA data

; Translate and set pixel values
pixels: mov     ah,[DS:SI]      ;Get 2 pixels
        push    ax
        and     ah,0F0h         ;Get 1st pixel
        shr     ah,1            ;4 shr reg8,1's are faster than one
        shr     ah,1            ;mov reg8,abs8 + shr ah,cl
        shr     ah,1
        shr     ah,1
        mov     [ES:DI],ah      ;Put our pixel
        inc     di
        pop     ax              ;Faster than mov'ing ax again...
        and     ah,0Fh          ;Get 2nd pixel
        mov     [ES:DI],ah      ;And plot it (no translation required)
        inc     di
        inc     si
        cmp     si,7d00h        ;Have we done all the pixels?
        jne     pixels

; Translate and set color palettes - note that this is not exact, but close
; Hella-fast colors thanks to Midnight and MYDE.ASM
pall:   mov     si,offset pals  ;DS:SI -> Palette data
        xor     bx,bx
llp:    mov     dx,03c8h
        mov     ax,bx
        out     dx,al
        mov     ax,[DS:SI]      ;Fetch the word
        and     ax,0F00h        ;Get Red Intensity
        mov     cl,6            ;shr 6 = shr 8, mul 4
        shr     ax,cl           ;shr is faster than shr, mul
        mov     dx,03c9h
        out     dx,al
        mov     ax,[DS:SI]      ;Get the word again
        and     ax,00F0h        ;This time, get Green Intensity
        mov     cl,2
        shr     ax,cl
        out     dx,al
        mov     ax,[DS:SI]
        and     ax,000Fh        ;get Blue intensity
        mov     cl,2
        shl     ax,cl
        out     dx,al
        inc     bx
        add     si,2
        cmp     bx,256          ;Do all the colors...
        jne     llp

; Check for fill-mode and set pixels accordingly
fill:   mov     si,offset scb
        xor     di,di
        xor     ch,ch           ;CH = scanline count
leep:   mov     al,[ds:si]
        and     al,00100000b    ;Fill mode set?
        cmp     al,00
        jne     fmode
        add     di,320
        jmp     nextf
fmode:  xor     bx,bx           ;BX = pixel count
        xor     dl,dl
flp:    mov     al,[es:di]
        cmp     al,00h
        jne     nof
        mov     [es:di],dl
        jmp     f2
nof:    mov     dl,al
f2:     inc     di
        inc     bx
        cmp     bx,320
        jne     flp
nextf:  inc     ch
        inc     si
        cmp     ch,200
        jne     leep


; Read the SCBs and translate scanline colors accordingly
colorx: mov     si,offset scb   ;DS:SI -> SCBs
        xor     di,di
        xor     ch,ch
doobie: mov     al,[ds:si]      ;Get the scb
        and     al,0Fh          ;Mask off the palette value
        cmp     al,00           ;If palette 0, no translation needed
        jne     over1
        add     di,320
        jmp     next
over1:  shl     al,1            ;Shl is faster than mul for multiplication
        shl     al,1            ;Why do we do this 4 times rather than use cl?
        shl     al,1            ;shl reg8,cl(4) = 9 cycles + 2 for the mov
        shl     al,1            ;shl 4 times = 8 cycles
        xor     bx,bx
xl:     add     [es:di],al      ;Do the color translation
        inc     bx
        inc     di
        cmp     bx,320
        jne     xl
next:   inc     ch
        inc     si
        cmp     ch,200          ;Done all the lines?
        jne     doobie          ;Nope...

dndn:   xor     ah,ah
        int     16h             ;Get keypress

        mov     ax,03h
        int     10h             ;So we go back to text...

        mov     ax,04c00h
        int     21h             ;Return to DOS, return code 0

; Procedure to read in the $C1 file...
; Uses Fiver's DOS calls
Proc    readit
        mov     ax,@data
        mov     ds,ax
        mov     dx,offset fnam
        xor     al,al
        call    fopen
        jc     oerr
suc:    push    bx
        mov     cx,8000h
        mov     dx,offset picdata
        call    fread
        pop     bx
        call    fclose
        ret
oerr:   mov     dx,offset emsg
        call    puts_z
        mov     ax,04c01h
        int     21h
readit  endp

; Fiver's DOS library
; By Fiver - June 1993

proc    fseek   ; accepts the following
                ; al - origin (0 : start, 1: current, 2: end)
                ; bx - file handle
                ; cx:dx offset (usually dx only for less that 65000<>)
        push    ax dx
        mov     ah,042h
        int     21h
        pop     dx ax
        ret
        endp    fseek

proc    fread   ; accepts the following
                ; bx - file handle
                ; cx - number of bytes to read
                ; ds:dx - buffer for data
        push    ax
        mov     ah,03fh
        int     21h
        pop     ax
        ret
        endp    fread

proc    fopen   ; accepts the following
                ; ds:dx - asciiz filename
                ; al - mode (0 : read only, 1 : write only, 2 : read/write)
                ; returns file handle in bx
        push    ax cx
        xor     cx,cx
        mov     ah,03dh
        int     21h
        mov     bx,ax   ; filehandle returned in ax, move to bx for standard
        pop     cx ax
        ret
        endp    fopen

proc    fclose  ; accepts the following
                ; bx - file handle
        push    ax
        mov     ah,03eh
        int     21h
        pop     ax
        ret
        endp    fclose

proc    fwrite  ; accepts the following
                ; bx - file handle
                ; ds:dx - buffer to write
                ; cx - number of bytes to write
        push    ax
        mov     ah,040h
        int     21h
        pop     ax
        ret
        endp    fwrite

proc    gets_z          ; accepts ds:dx as a input buffer
                        ; cx - maximum string length
        push    es di ax bx dx cx
        mov     ax,ds
        mov     es,ax
        mov     di,dx
        xor     al,al
        cld
        rep     stosb
        pop     cx
        push    cx
        xor     bx,bx
        mov     ax,ds
        mov     es,ax
        mov     di,dx
        call    fread
        pop     cx
        push    cx
        @@no13:
        mov     al,[es:di]
        cmp     al,13
        jne     @@not13
        xor     al,al
        mov     [es:di],al
        @@not13:
        inc     di
        loop    @@no13
        pop     cx dx bx ax di es
        ret
        endp    gets_z

proc    puts_z          ; accepts asciiz string in ds:dx
        pusha
        mov     ax,ds
        mov     es,ax
        mov     di,dx
        xor     cx,cx
        xor     al,al
        @@keepgoin:
        mov     al,[es:di]
        inc     di
        cmp     al,0
        je      @@endgoin
        inc     cx
        jmp     @@keepgoin
        @@endgoin:
        mov     bx,1
        call    fwrite
        popa
        ret
        endp    puts_z

End     Start
