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 #cos2 55 , 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.

Write a Comment