1. Copperbars

This is the first coding example I upload here. This is an old effect the Amiga was very famous for: the copperbars, or rasterbars.

These bars were very easy to do on an Amiga, as all that was needed was to put color values paired with the coloraddress into a copperlist. When the copperlist was done, the processor didn't need to do any more during that frame with colorchanges or anything. The special chips in the Amiga took care of it all.

More info about the Copper.


Download LHA-package.

This demo uses the Copper to change the background colors according to how 3 virtual rasterbars are moving in a circular manner. There isn't any real fancy coding behind this, the code is quite easy to read as no real codeoptimization is done.
The circular movements that are in the demo are made with pre-calculated sinus- and cosinustables, the trigonometrytabels are 360 degrees (or 2pi) projected onto 256 bitgrads. The amplitudes and zero-axis are modified to suite assemblycoding with integers, for example the cos255-table has an amplitude of 127 and zero-axis of 128. This gives a table with integervalues in the range of [0,255], and thus a byte is sufficent to store the value.

The 3 copperbars are moving up-and-down according to a pre-calced sinus-table, called sin255_60. This table is made up mostly in the same manner as the cos255-table, but here the amplitude is 30 and the values of the table are [0,60]. This makes an circle with a radius of 30.
The copperbars are 30px high with each row having an own colorvalue (execpt the two in the middle have the same colorvalue). Each of the bars have pure red, green or blue colors, this is used as an other effect.

Sinus is used to calculate the height-position of the bars and cosinus as depth-position. If we could look into the monitor from the side, the bars would seem to make a perfect circle in their movement. This isn't suprising if you know about the "unit circle" of trigonometry. The Copperbars could be made to move in many different patterns.

    ; change angles according to anglespeed
    move.b anglespeed,d1
    move.l #sin255_60,a0
    move.l #cos255,a1
    move.l #cbar_a,a2
    move.l #cbar_y,a3
    move.l #cbar_z,a4
    move.b #4,d2
        move.b (a2),d3         ; angle
        add.b d1,d3             ; angle + anglespeed
        move.b (a0,d3),d4      ; y from sintable
        move.b (a1,d3),d5       ; z from costable
        move.b d3,(a2)+        ; angle
        move.b d4,(a3)+        ; y
        move.b d5,(a4)+        ; z
        subq.b #1,d2
        bne loop_copperbars

Here we can see from the source how the sin255_60 and cos255 tables are used as lookup tables for values. Cbar_a is angle, _y is height position and _z is depth position. The fetched values are then stored into memory for later processing.
After this we have to get the relative positions of the bars correct according to their depth position. This is a matter of sorting the bars from largest to smallest depthvalue. As here is only 3 bars used, I didn't write a sorting routine, but merely compairing 3 pairs of bars can sort it out without a routine, this is a little messy, but efficient.

    ; get z-value for all bars
    move.l #0,copperbars_z    ; 0 to z for all 3 bars
    move.l #cbar_z,a2
    move.b (a2)+,d1
    move.b (a2)+,d2
    move.b (a2)+,d3
    moveq #0,d4        ; z red
    moveq #0,d5        ; z grn
    moveq #0,d6        ; z blu
    ; compare z-values
    cmp.b d1,d2
    bcc z1
    addq #1,d5
    bra z1e
    addq #1,d4
    cmp.b d1,d3
    bcc z2
    addq #1,d6
    bra z2e
    addq #1,d4
    cmp.b d2,d3
    bcc z3
    addq #1,d6
    bra z3e
    addq #1,d5
    move.l #cbar_z,a2
    move.b d4,(a2)+        ; red
    move.b d5,(a2)+        ; grn
    move.b d6,(a2)+        ; blu

Registers d1 & d4 are for the RED-bar, d2 & d5 are for the GRN-bar and d3 & d6 are or the BLU-bar. In each comparison the "color" with the larger value will get an 1 added to its companion register d(n+3). After this the values stored for depth are 0, 1, 2 and these values are easy to use for testing agaist an iterative index in a loop.
In the iterative loop all the rasterlines are put into an array in the correct order: the lowest first and then the others painted over. The routine could be optimized to not paint the same line in the array many times, but as I wanted a special "addative"/"ORed"-mode for painting as well, the optimizition doesn't work. The "addative"-mode plays with logigal-OR to get more colors from the copperbars, but at the same time the "3D"-illusion of the bars is gone.

            cmp.b #0,cbar_mode
            bne cbar_additive
            move.w (a2)+,(a3)+
            bra cbar_normal
            move.w (a2)+,d1
            ori.w d1,(a3)+
            subq.b #1,d7
            bne loop_copperline_render

In this codesnippet the difference between normal "overpainting" of lines in the array and the "addative" ORed value. Red or Grn = Yel, Grn or Blu = Cya, Blu or Red = Mag and different hues of those colors. But at this time everything is still "painted" into an array, not a copperlist.

    move.l #copperlines1,a2
    move.w cbar_start,d3        ; startline 
    move.w #0,d7
        move.w d3,d4
        add.w d7,d4
        cmp.w #256,d4          ; PAL needs a trick to handle more than 256 lines in overscan 
        bne no_PAL_fix
        move.l #$ffdffffe,(a6)+
        ; wait
        move.w d7,d4           ; d4=d7
        add.w d3,d4            ; d4=d7+d3 (d7+startline)
        lsl.w #8,d4            ; d4=(d7+startline)<<8
        add.w #$07,d4          ; d4=(d7+startline)<<8+07
        move.w d4,(a6)+        ; Wait - first line ex: $6407
        move.w #$fffe,(a6)+    ; Mask
        ; color
        move.w #$0180,(a6)+    ; Color0
        move.w (a2)+,(a6)+     ; Colordata
        addq.w #1,d7
        cmp.w #90,d7
        bcs loop_rasterlines_copper

Addressregister a6 is here a pointer to the copperlist that is being generated.