The 6-sprite asymmetric playfield "title screen" routine

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andrew Davie

A couple of years ago I was working on my chess display, and wanted to put some text overlay on top of the asymmetric playfield. I did not manage to get this working - simply not enough processing time on the scanline to change 6 PF registers + 6 sprite shapes + 3 colour (PF, sprite 0, sprite 1).  However, I did manage to get it working if I used a mirrored playfield and dropped the left/right 4 pixels.

So, this is that - a 32-PF pixel asymmetric playfield with colour change on every scanline + an overlaid 6-sprite routine also with a colour change on every line.  I found only one horizontal position where this all worked perfectly, though I have not extensively tested to try other positions. The positioning is somewhat determined by the positions in which PF writes must be updated, and also of course the sprite graphics writes.  What you see here is a bit of luck; my first implementation did not work (sprites garbled), but the second - after a little bit of shuffling of the kernel - worked perfectly. 

Here's the kernel code...


                    ldx #%00110011
                    stx NUSIZ0                      ; three copies close, missile x8
                    stx NUSIZ1                      ; three copies close, missile x8
                    stx VDELP0                      ; vertical delay on
                    stx VDELP1                      ; vertical delay on

OverScanMenu

    ; axiom: D2 of X == 1

                    sta WSYNC
                    stx VBLANK              ; video output off (D2 of X is 1 always!)


                    ldx kernel
                    cpx currentKernel
                    beq thisKernel

                    jmp startAnyKernel
thisKernel


                    ldx tv_type
                    lda TimerOS,x
                    clc
                    adc #1
                    sta TIM64T              ; set timer for OS

                    lda #_DS_AUDV0
                    sta AUDV0
                    lda #_DS_AUDC0
                    sta AUDC0
                    lda #_DS_AUDF0
                    sta AUDF0

                    lda #_DS_AUDV0
                    sta AUDV1
                    lda #_DS_AUDC0
                    sta AUDC1
                    lda #_DS_AUDF0
                    sta AUDF1


    IF _ENABLE_ATARIVOX
        jsr speakJet
    ENDIF

                    ldy #_FN_MENU_OS
processArmOSMenu    jsr CallArmCode
                    ldy #_FN_MENU_IDLE
                    jsr CallArmCode
                    ;jsr safeTimerCheck
                    ;tmp bcs processArmOSMenu

safeTimerWait2      lda INTIM
                    bpl safeTimerWait2
                    ;jsr safeTimerWait


VerticalSyncMenu

                    ldy #2

                    ldx tv_type
                    lda TimerVB,x

                    sty WSYNC

; --- start scanline 1 of Vertical Sync ---

                    sty VSYNC           ; turn on Vertical Sync signal
                    sta TIM64T
                    sty WSYNC

; --- start scanline 2 of Vertical Sync ---

                    ; use otherwise wasted time to zero out some TIA registers

                    ldx #0              ; 2  2
                    stx PF0             ; 3 17
;                    stx CTRLPF          ; 3 26
                    stx WSYNC           ; 3 29/0

; --- start scanline 3 of Vertical Sync ---



    ; IF _ENABLE_ATARIVOX
    ;     jsr speakJet
    ; ENDIF


                    ldy #_FN_MENU_VB
                    stx WSYNC           ; end of VerticalSync scanline 3
                    stx VSYNC           ; turn off Vertical Sync signal
                    jsr CallArmCode

                    ldx #1
vbSetInitialMenu    lda #DSCOMM                 ; P1_X, P0_X

PosObject

    ; A = X position value
    ; X = 0=P0, 1=P1, 2=M0, 3=M1, 4=Ball

                    sec
                    sta WSYNC
DivideLoop          sbc #15
                    bcs DivideLoop

                    eor #7
                    asl
                    asl
                    asl
                    asl
                    sta.wx HMP0,X
                    sta RESP0,X

                    dex
                    bpl vbSetInitialMenu

                    lda #DSCOMM
                    sta tv_type                 ; _TV_TYPE = NTSC, PAL, PAL-60, SECAM
                    lda #DSCOMM
                    sta kernel
                    lda #DSCOMM
                    sta COLUBK

                    sta WSYNC
                    sta HMOVE




processArmVBMenu    ldy #_FN_MENU_IDLE
                    jsr CallArmCode
                    ;jsr safeTimerCheck
                    ;tmp bcs processArmVBMenu
                    ;jsr safeTimerWait
safeTimerWait3      lda INTIM
                    bpl safeTimerWait3


                    ldx #0
                    stx VBLANK              ; video output on
                    stx PF0

                    ldx #%00000001
                    stx CTRLPF              ; reflect PF

                    lda #_DS_COLUPF
                    sta COLUPF

                    sta WSYNC
    ;                sta WSYNC
                    jmp FASTJMP1


_MENU_KERNEL

;@3

                    lda #_DS_PF1_LEFT
                    sta PF1                         ; 5
                    lda #_DS_GRP0a
                    sta GRP0                        ; 5
                    lda #_DS_GRP1a
                    sta GRP1                        ; 5
                    lda #_DS_GRP0b
                    sta GRP0                        ; 5

                    lda #_DS_GRP1c                  ; 2
                    tay                             ; 2

                    lda #_DS_PF2_LEFT
                    sta PF2                         ; 5

                    lda #_DS_GRP0c                  ; 2
                    tax                             ; 2
                    lda #_DS_PF1_RIGHT
                    sta PF1                         ; 5
;@41
                    lda #_DS_PF2_RIGHT              ; 2
                    nop                             ; 2
                    sta PF2                         ; 3

                    lda #_DS_GRP1b                  ; 2
                    sta GRP1                        ; 3
                    stx GRP0                        ; 3
                    sty GRP1                        ; 3
                    sta GRP0                        ; 3

;@62

                    lda #_DS_COLUP0                 ; 2
                    sta COLUP0                      ; 3
                    sta.w COLUP1                    ; 4

                    lda #_DS_COLUPF                 ; 2
                    sta COLUPF                      ; 3
;@76=0

                    jmp FASTJMP1                    ; 3

;@3--> start of line again :)


_EXIT_MENU_KERNEL

                    ldx #2
                    stx VBLANK
                    ldy #0
                    sty PF1
                    sty PF2

                    jmp OverScanMenu

; EOF


As you can see, it's CDFJ-centric, using data streams to retrieve graphics data rapidly.  The "magic" starts at the label _MENU_KERNEL.

I'm happy for others to use this idea/code. A simple acknowledgement if you use my code would be all I'd expect.

Here's a screenshot of it in action - you see the menu text right-of-center. In reality, this is a vertical strip of 6 sprites occupying the entire screen height, so you can put graphics/text there to your heart's content.





Prizrak

Looks good, I know some of this stuff drives you a bit crazy till you figure it out. I'm always thoroughly impressed with the wizardry you pull off

alex_79

Quote from: Prizrak on 17 Sep 2023, 11:49 AMI'm always thoroughly impressed with the wizardry you pull off
Me too.

Thanks for sharing!