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.

THIS DEMO

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.

 161 
    ; change angles according to anglespeed
 162 
    move.b anglespeed,d1
 163 
    move.l #sin255_60,a0
 164 
    move.l #cos255,a1
 165 
    move.l #cbar_a,a2
 166 
    move.l #cbar_y,a3
 167 
    move.l #cbar_z,a4
 168 
    move.b #4,d2
 169 
    loop_copperbars:
 170 
        move.b (a2),d3         ; angle
 171 
        add.b d1,d3             ; angle + anglespeed
 172 
        move.b (a0,d3),d4      ; y from sintable
 173 
        move.b (a1,d3),d5       ; z from costable
 174 
        move.b d3,(a2)+        ; angle
 175 
        move.b d4,(a3)+        ; y
 176 
        move.b d5,(a4)+        ; z
 177 
        subq.b #1,d2
 178 
        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.

 180 
    ; get z-value for all bars
 181 
    move.l #0,copperbars_z    ; 0 to z for all 3 bars
 182 
    move.l #cbar_z,a2
 183 
    move.b (a2)+,d1
 184 
    move.b (a2)+,d2
 185 
    move.b (a2)+,d3
 186 
    moveq #0,d4        ; z red
 187 
    moveq #0,d5        ; z grn
 188 
    moveq #0,d6        ; z blu
 189 
    ; compare z-values
 190 
    cmp.b d1,d2
 191 
    bcc z1
 192 
    addq #1,d5
 193 
    bra z1e
 194 
    z1:
 195 
    addq #1,d4
 196 
    z1e:
 197 
    cmp.b d1,d3
 198 
    bcc z2
 199 
    addq #1,d6
 200 
    bra z2e
 201 
    z2:
 202 
    addq #1,d4
 203 
    z2e:
 204 
    cmp.b d2,d3
 205 
    bcc z3
 206 
    addq #1,d6
 207 
    bra z3e
 208 
    z3:
 209 
    addq #1,d5
 210 
    z3e:
 211 
    move.l #cbar_z,a2
 212 
    move.b d4,(a2)+        ; red
 213 
    move.b d5,(a2)+        ; grn
 214 
    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.

 253 
        loop_copperline_render:
 254 
            cmp.b #0,cbar_mode
 255 
            bne cbar_additive
 256 
            move.w (a2)+,(a3)+
 257 
            bra cbar_normal
 258 
            cbar_additive:
 259 
            move.w (a2)+,d1
 260 
            ori.w d1,(a3)+
 261 
            cbar_normal:
 262 
            subq.b #1,d7
 263 
            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.

 271 
    move.l #copperlines1,a2
 272 
    move.w cbar_start,d3        ; startline 
 273 
    move.w #0,d7
 274 
    loop_rasterlines_copper:
 275 
        move.w d3,d4
 276 
        add.w d7,d4
 277 
        cmp.w #256,d4          ; PAL needs a trick to handle more than 256 lines in overscan 
 278 
        bne no_PAL_fix
 279 
        move.l #$ffdffffe,(a6)+
 280 
        no_PAL_fix:
 281 
        ; wait
 282 
        move.w d7,d4           ; d4=d7
 283 
        add.w d3,d4            ; d4=d7+d3 (d7+startline)
 284 
        lsl.w #8,d4            ; d4=(d7+startline)<<8
 285 
        add.w #$07,d4          ; d4=(d7+startline)<<8+07
 286 
        move.w d4,(a6)+        ; Wait - first line ex: $6407
 287 
        move.w #$fffe,(a6)+    ; Mask
 288 
        ; color
 289 
        move.w #$0180,(a6)+    ; Color0
 290 
        move.w (a2)+,(a6)+     ; Colordata
 291 
        ;
 292 
        addq.w #1,d7
 293 
        cmp.w #90,d7
 294 
        bcs loop_rasterlines_copper

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