View Single Post
Old 28 January 2012, 18:32   #52
Mrs Beanbag
Glastonbridge Software
Mrs Beanbag's Avatar
Join Date: Jan 2012
Location: Edinburgh/Scotland
Posts: 2,202
As promised - sine scroller source code! Requires some graphics memory to be passed to it, and a sine table. The blitting is adaptive, the shallower the sinewave the fewer blits it does. About 3 blits per 16 pixel slice seems typical. Everything between "Loop" and "doBlit" could be pre-calculated and stored in look-up tables.

bltapt    =    $50
bltcpt    =    $48
bltdpt    =    $54
bltafwm    =    $44
bltalwm    =    $46

bltcmod    =    $60
bltamod    =    $64
bltdmod    =    $66

bltcon0    =    $40
bltcon1    =    $42
bltsize    =    $58

bltbdat    =    $72

Height    =    32

* MERGE macro for chunky to planar routine
* takes two registers and swaps the bits
* specified by the mask.
merge    MACRO
    move.l    \1,D5
    eor.l    \2,D5
    and.l    \3,D5
    eor.l    D5,\1
    eor.l    D5,\2

* in:
* A0 - destination bitplane
* A1 - source bitplane
* A2 - source sine table (bytes)
* out:
* D6 counts the number of blits

    movem.l    A3-A6,-(SP)

    lea    $DFF000,A6
    moveq    #19,D7
    clr.l    D6

Loop    clr.l    D0
    clr.l    D1

    moveq    #15,D5
    move.l    A2,A3

.base    move.b    (A3)+,D1    ; look at the next 16 values
    cmp    D1,D0    ; and find the lowest Y-coordinate
    bge.s    .ge    ; (i.e. highest numerical value)
    move    D1,D0    
.ge    dbra    D5,.base

    move    D0,D1
    mulu    #40,D1

    addq.b    #1,D0
    and    #$F,D0
    move    D0,D2
    lsl    #8,D2
    or    D2,D0

    move    D0,D2
    swap    D0
    move    D2,D0

    lea    (A0,D1),A5    ; it is the user's responsiblity
    movem.l    (A2)+,D1-D4    ; not to let it go over the edge

calcMasks            ; Chunky to planar routine.
    sub.l    D0,D1    ; These masks are used to slice up
    sub.l    D0,D2    ; each 16-pixel column and scroll
    sub.l    D0,D3    ; multiple single-pixel columns at once
    sub.l    D0,D4    ; in worst-case log_2(n) time

    not.l    D1    ; Mentally keeping track of all the
    not.l    D2    ; bits was a nightmare but it looks
    not.l    D3    ; intuitively right, and it works
    not.l    D4    ; so don't ask too many questions.
            ; (We could precalculate all of these.)

    move.l    #$0F0F0F0F,D0
    and.l    D0,D1
    and.l    D0,D2
    and.l    D0,D3
    and.l    D0,D4
    lsl.l    #4,D1
    lsl.l    #4,D3
    or.l    D2,D1
    or.l    D4,D3
    ror.l    #8,D3
    merge    D1,D3,#$00FF00FF
    rol.l    #8,D3

    move    D1,D2
    swap    D2
    move    D3,D2
    swap    D3
    move    D3,D1

    ror.l    #2,D2
    merge    D1,D2,#$33333333
    rol.l    #2,D2

    move    D1,D3
    swap    D3
    move    D2,D3
    swap    D2
    move    D2,D1
    ror.l    #1,D3
    merge    D1,D3,#$55555555
    rol.l    #1,D3
doBlit    bsr    _waitblit        ; Wait for the blitter

    move    #38,bltcmod(A6)
    move    #38,bltamod(A6)
    move    #38,bltdmod(A6)
    move.l    #-1,bltafwm(A6)

    lea    40*1(A1),A4    ; The first blit copies the data
    lea    -40*1(A5),A5    ; from the source onto the screen.
    move.l    A1,bltapt(A6)    ; The mask selects which slices to
    move.l    A4,bltcpt(A6)    ; place 1 pixel higher than the others.
    move.l    A5,bltdpt(A6)    ; Leave a blank line above the source!

    move.l    #$0BB80000,bltcon0(A6)
    move    D3,bltbdat(A6)    ; the mask goes in bltbdat
    move    #64*(Height+1)+1,bltsize(A6)
    addq    #1,D6        ; count how many blits we did

.blit1    tst    D1
    beq.s    .blit2        ; we can skip if the mask is empty
    bsr    _waitblit

    move.l    A5,bltcpt(A6)
    lea    -40*2(A5),A5    ; move selected slices by 2 pixels
    move.l    A5,bltapt(A6)
    move.l    A5,bltdpt(A6)
    move    D1,bltbdat(A6)
    move    #64*(Height+3)+1,bltsize(A6)    ; BLIT
    addq    #1,D6

.blit2    swap    D3
    tst    D3
    beq.s    .blit3
    bsr    _waitblit

    move.l    A5,bltcpt(A6)
    lea    -40*4(A5),A5    ; move selected slices by 4 pixels
    move.l    A5,bltapt(A6)
    move.l    A5,bltdpt(A6)
    move    D3,bltbdat(A6)
    move    #64*(Height+7)+1,bltsize(A6)
    addq    #1,D6

.blit3    swap    D1
    tst    D1
    beq.s    .next
    bsr    _waitblit

    move.l    A5,bltcpt(A6)
    lea    -40*8(A5),A5    ; move selected slices by 8 pixels
    move.l    A5,bltapt(A6)
    move.l    A5,bltdpt(A6)

    move    D1,bltbdat(A6)
    move    #64*(Height+15)+1,bltsize(A6)
    addq    #1,D6

.next    addq.l    #2,A0
    addq.l    #2,A1

    dbra    D7,Loop

    bsr    _waitblit
    movem.l    (SP)+,A3-A6
    move    #$8400,$96(A6)    ; might as well give the blitter
                ; priority while we're waiting for it
    btst    #6,$2(A6)
.bl    btst    #6,$2(A6)
    bne.s    .bl

    move    #$0400,$96(A6)
Note this is hard-coded for 320-wide screens! But you can work that out...

Last edited by Mrs Beanbag; 28 January 2012 at 18:36. Reason: p.s.
Mrs Beanbag is offline  
Page generated in 0.04864 seconds with 9 queries