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.
THIS DEMO
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.
Write a Comment