; Dots tunnel, version 2 : la v1 avec deux écrans, pour ne plus clignoter.
; Les tables viennent du fichier sauvé par le BASIC.
; rasm tunnel-v2-fr.asm -o tunnel-v2 écrit tunnel-v2.sna.

        buildsna
        bankset 0

YLO = #4000                     ; la carte mémoire de tables.bas
YHI = #4100
CENTER = #4200
SHAPE = #4A00
RINGS = 16
DOTS = 16

; Couleurs du Gate Array (#40 + numéro de la couleur matérielle)
BLACK = #54
BLUE = #44
SKY_BLUE = #57
BRIGHT_WHITE = #4B
RED = #4C

        macro border,colour
        ld bc,#7F10             ; Gate Array : choisit la bordure
        out (c),c
        ld a,{colour}
        out (c),a
        mend

        org YLO
        incbin "TABLES.BIN",128         ; sans le header AMSDOS de 128 octets

        org #1000
        run start

start:  di
        ld sp,#1000
        call init

main:   call wait_vbl
        ld a,(back)
        call show_screen        ; affiche l'écran qu'on vient de dessiner
        ld a,(back)
        xor #40                 ; #C0 <-> #80
        ld (back),a             ; et dessine dans l'autre

        border RED              ; début du travail

        ld a,(back)
        ld h,a                  ; l'écran de travail, caché
        ld l,0
        call clear16k

        ld hl,t
        inc (hl)
        ld a,(hl)
        neg
        and 63
        ld (depth),a            ; anneau 0 : d = -t and 63

        ld a,RINGS
        ld (ring),a
ring_loop:
        call ring_setup         ; ringX, ringY, pen, et IX = SHAPE de l'anneau
        ld a,DOTS
        ld (dot),a
dot_loop:
        ld a,(ringX)
        add a,(ix+0)            ; x = ringX + dx
        ld b,a
        ld a,(ringY)
        add a,(ix+1)            ; y = ringY + dy
        ld c,a
        ld a,(pen)
        ld e,a
        call plot
        inc ix
        inc ix
        ld hl,dot
        dec (hl)
        jr nz,dot_loop

        ld a,(depth)            ; anneau suivant : d + 4
        add a,4
        and 63
        ld (depth),a
        ld hl,ring
        dec (hl)
        jr nz,ring_loop

        border BLACK            ; fin du travail
        jp main

; ring_setup : lit le centre, l'encre et l'adresse de la forme de l'anneau d.
ring_setup:
        ld a,(depth)
        ld c,a
        and #3C                 ; (d >> 2) * 4
        ld l,a
        ld h,0
        add hl,hl
        add hl,hl
        add hl,hl
        add hl,hl
        add hl,hl               ; (d >> 2) * 128
        ld a,(t)
        add a,c
        and #FC
        rrca                    ; phase * 2, phase = ((t + d) >> 2) and 63
        or l
        ld l,a
        ld a,h
        add a,CENTER>>8
        ld h,a
        ld a,(hl)
        ld (ringX),a
        inc hl
        ld a,(hl)
        ld (ringY),a

        ld a,c                  ; pen = PENS(d >> 4)
        rlca
        rlca
        rlca
        rlca
        and 3
        ld e,a
        ld d,0
        ld hl,PENS
        add hl,de
        ld a,(hl)
        ld (pen),a

        ld a,(t)                ; IX = SHAPE + d * 128 + rot * 32
        and #0C
        rlca
        rlca
        rlca                    ; rot * 32, rot = (t >> 2) and 3
        ld e,a
        ld a,c
        srl a                   ; A = d >> 1, retenue = d and 1
        jr nc,even_depth
        set 7,e                 ; + 128 si d est impair
even_depth:
        add a,SHAPE>>8
        ld d,a
        push de
        pop ix
        ret

; plot : allume le pixel (B, C) avec l'encre E (4 pixels de la même encre).
plot:   ld a,b
        and 3                   ; rang du pixel dans son octet
        ld d,#88                ; bits du pixel de gauche
        jr z,mask_ink
next_pixel:
        srl d
        dec a
        jr nz,next_pixel
mask_ink:
        ld a,d
        and e
        ld e,a                  ; bits du pixel, dans l'encre

        ld a,b
        srl a
        srl a                   ; colonne d'octet : x >> 2
        ld h,YLO>>8
        ld l,c
        add a,(hl)              ; + poids faible de la ligne
        ld b,a
        inc h                   ; YHI = YLO + 256
        ld a,(back)
        adc a,(hl)              ; + poids fort, retenue et début de l'écran
        ld h,a
        ld l,b
        ld a,e
        or (hl)                 ; garde les autres pixels de l'octet
        ld (hl),a
        ret

; init : mode 1, ROM coupées, palette.
init:   ld bc,#7F8D
        out (c),c
        ld hl,palette
        ld e,0
next_ink:
        out (c),e               ; E < #10 : choisit l'encre E
        ld a,(hl)
        out (c),a               ; #40 à #5F : lui donne sa couleur
        inc hl
        inc e
        ld a,e
        cp 4
        jr nz,next_ink
        ld a,#10                ; choisit la bordure
        out (c),a
        ld a,BLACK
        out (c),a
        ret

clear16k:                       ; efface 16 Ko à partir de HL (L = 0)
        ld d,h
        ld e,1
        ld (hl),0
        ld bc,#3FFF
        ldir
        ret

; show_screen : le CRTC affichera l'écran de poids fort A (#C0 ou #80)
; à partir de la prochaine image.
show_screen:
        ld bc,#BC0C             ; CRTC : choisit le registre 12
        out (c),c
        rrca
        rrca
        and #30                 ; #C0 -> #30, #80 -> #20
        inc b                   ; #BD : écrit dans le registre
        out (c),a
        ret

; wait_vbl : attend le début du retour de trame.
wait_vbl:
        ld b,#F5                ; PPI port B, bit 0 = VBL
vbl_end:
        in a,(c)
        rra
        jr c,vbl_end            ; déjà dans la VBL : attend sa fin
vbl_start:
        in a,(c)
        rra
        jr nc,vbl_start
        ret

palette:
        db BLACK,BLUE,SKY_BLUE,BRIGHT_WHITE
PENS:   db #FF,#0F,#F0,#F0      ; 4 pixels d'encre 3, 2, 1, 1 selon d >> 4

back:   db #C0                  ; poids fort de l'écran de travail
t:      db 0
depth:  db 0
ring:   db 0
dot:    db 0
ringX:  db 0
ringY:  db 0
pen:    db 0
