;---------------------------------------------------------------------
; COPPER3 - 3 simultaneous copper bars, 79 bytes! - final version by
; Tylisha C. Andersen - notable contributions by T.Remmel and J.Neil
;---------------------------------------------------------------------

b       equ <byte ptr>
w       equ <word ptr>

.model tiny
.code
org 100h

;---------------------------------------------------------------------

main:   pop   bx                ; zero bx by popping the return address
                                ;
m_1:    push  bx                ; write 3 positions and increments
        inc   bx                ; the jpo instruction jumps when there are
        push  bx                ; an odd number of set bits in the lower 8
        jpo   m_1               ; bits of the result;  this is true for
                                ; 1 (01b) and 2 (10b), but false for 3 (11b)
                                ;
m_2:    cli                     ; disable interrupts
        mov   ah, 8             ; ah = 8 for vertical retrace
        mov   cx, 390           ; for each of 390 scanlines:
                                ;
m_3:    mov   dx, 03DAh         ; dx = IS1 port, wait for retrace
m_4:    in    al, dx            ; retrace could be vertical or horizontal
        and   al, ah            ; due to the design of the VGA this ends in
        jnz   m_4               ; the horizontal retrace if ah = 01h, but in
m_5:    in    al, dx            ; the active vertical period if ah = 08h,
        and   al, ah            ; which is exactly what we need
        jz    m_5               ;
        mov   dl, 0C8h          ; dx = DAC write select port
        xchg  ax, bx            ; al = 0, select DAC register 0
        out   dx, al            ;
        inc   dx                ;
                                ;
        mov   si, sp            ; si = ptr. to position data list
        mov   bl, 3             ; for each of 3 colors:
                                ;
m_6:    lodsw                   ; ax = increment - tricky use of loop,
        loop  m_7               ; jumps when cx <> 1 to test for last line
                                ; if on last scanline, then
        sub   [si], ax          ; add increment to position, if this puts it
        cmp   w [si], -263      ; out of range, then bounce
        ja    m_7               ; 263 is the max. position of the top of a
        neg   w [si-2]          ; bar without it going off the screen
                                ;
m_7:    inc   cx                ; restore cx (it was decremented by 'loop')
        lodsw                   ; ax = position, si now = next color
        add   ax, cx            ; ax = line + position
        cmp   ax, 127           ; if it's not inside the bar, then set the
        jbe   m_8               ; color to 0 (xor al,al);  otherwise...
        xor   al, al            ;
m_8:    cmp   al, 64            ; if it's greater than 64, this means it's
        jb    m_9               ; on the top part where it is fading out, so
        not   al                ; we negate it (the top 2 bits are ignored)
                                ;
m_9:    out   dx, al            ; set color intensity, and loop (remember,
        dec   bx                ; parity is only on the lower 8 bits, so it
        jpo   m_6               ; doesn't matter what bh contains)
                                ;
        mov   ah, 1             ; ah = 01h for horiz. retrace, key check
        loop  m_3               ; loop
        int   16h               ; check for key press (enables interrupts)
        jz    m_2               ; loop while no key pressed
        int   20h               ; return to DOS

end main
