# ------------------------------------------------------------------- # BLITTER TUTORIAL (c) Copyright 1996 Nat! & KKP # ------------------------------------------------------------------- # These are some of the results/guesses that Klaus and Nat! found # out about the Jaguar with a few helpful hints by other people, # who'd prefer to remain anonymous. # # Since we are not under NDA or anything from Atari we feel free to # give this to you for educational purposes only. # # Please note, that this is not official documentation from Atari # or derived work thereof (both of us have never seen the Atari docs) # and Atari isn't connected with this in any way. # # Please use this informationphile as a starting point for your own # exploration and not as a reference. If you find anything innacurate, # missing, needing more explanation etc. by all means please write # to us: # nat@zumdick.rhein-main.de # or # kkp@gamma.dou.dk # # If you could do us a small favor, don't use this information for # those lame flamewars on r.g.v.a or the mailing list. # # HTML soon ? # ------------------------------------------------------------------- # $Id: tutorial.txt,v 1.4 1996/01/27 15:22:58 nat Exp $ # ------------------------------------------------------------------- Blitter tutorial: =-=-=-=-=-=-=-=-= Here are a few examples, that should work. They haven't been tested (yet). (note: not the best code, but hopefully understandable) a) Clearing 256 bytes starting from $2000 -------------------------------------- .wait: move.l B_CMD,d0 ;; wait for blitter to finish ror.w #1,d0 ;; Check if blitter is idle bcc.b .wait ;; bit was clear -> busy move.l #$2000,A1_BASE ;; point to destination move.l #$0,A1_PIXEL ;; start in front move.l #PIXEL16|XADDPHR|PITCH1,A1_FLAGS ;; use 16bit pixels/phrasemode move.l #0,B_PATD ;; our value to draw move.w #1,d0 ;; we wanna draw 1 'line' swap d0 ;; in upper word move.w #256/2/4,d0 ;; and 256 bytes == 128 16-bit-pixels move.l d0,B_COUNT ;; == 32 phrases move.l #PATDSEL,B_CMD ;; use B_PATD to draw and GO b) Setting 256 bytes starting at $2001 to 0xFF: ------------------------------------------- move.l #$2000,A1_BASE ;; point to destination move.l #$1,A1_PIXEL ;; start at offset 1 move.l #PIXEL8|XADDPIX|PITCH1,A1_FLAGS ;; use 8bit pixels pixelmode move.l #$FF,B_PATD ;; our value to draw move.w #1,d0 ;; we wanna draw 1 'line' swap d0 ;; in upper word move.w #256,d0 ;; and 256 bytes == 256 8-bit-pixels move.l d0,B_COUNT move.l #PATDSEL,B_CMD ;; use B_PATD to draw and GO c) Copying 256 bytes from $2000 to $3000 ------------------------------------ move.l #$3000,A1_BASE ;; point to destination move.l #$0,A1_PIXEL ;; start in front move.l #PIXEL16|XADDPHR|PITCH1,A1_FLAGS ;; use 16bit pixels/phrasemode move.l #$2000,A2_BASE ;; point to source move.l #$0,A2_PIXEL ;; start in front move.l #PIXEL16|XADDPHR|PITCH1,A2_FLAGS ;; use 16bit pixels/phrasemode move.w #1,d0 ;; we wanna draw 1 'line' swap d0 ;; in upper word move.w #256/2/4,d0 ;; and 256 bytes == 128 pixels move.l d0,B_COUNT ;; == 32 phrases move.l #LFU_REPLACE|SRCEN,B_CMD ;; straight copy d) XORing 256 bytes from $2000 with $3000 ------------------------------------ as c) but move.l #LFU_XOR|DSTEN|SRCEN,B_CMD instead of move.l #LFU_REPLACE|SRCEN,B_CMD e) Gouraudshading a horizontal 64 pixel line on a 320x200 bitmap at $20000 starting at relative point 100,120 -------------------------------------------------------------- move.l #$20000,A1_BASE ;; point to destination move.w #120,d0 ;; Y pos swap d0 ;; in upper word move.w #100,d0 ;; X pos in lower move.l d0,A1_PIXEL ;; start in the middle move.l #PIXEL16|XADDPIX|WID320|PITCH1,A1_FLAGS ;; note the WID320!! move.w #$8000,B_PATD ;; starting color move.l #$00038000,B_IINC ;; intensity increment (3.5) move.w #1,d0 ;; we wanna draw 1 'line' swap d0 ;; in upper word move.w #64,d0 ;; and 64 pixels move.l d0,B_COUNT move.l #PATDSEL|GOURD,B_CMD f) Blitting a 64x64 piece from a 128x128 pixmap (Pos: 10, 20) unto a 320x200 pixmap with source shading (Pos: 100,120). The source is at $30000 the destination at $20000. -------------------------------------------------------------- move.l #$20000,A1_BASE ;; point to destination move.l #PIXEL16|XADDPIX|WID320|PITCH1,A1_FLAGS ;; note the WID320!! move.w #120,d0 ;; Y pos swap d0 ;; in upper word move.w #100,d0 ;; X pos in lower move.l d0,A1_PIXEL ;; start in the middle move.w #1,d0 swap d0 move.w #-64,d0 move.l d0,A1_STEP move.l #$30000,A2_BASE move.l #PIXEL16|XADDPIX|WID128|PITCH1,A2_FLAGS move.w #12,d0 ;; Y pos swap d0 ;; in upper word move.w #10,d0 ;; X pos in lower move.l d0,A2_PIXEL move.w #1,d0 swap d0 move.w #-64,d0 move.l d0,A2_STEP move.w #64,d0 ;; we wanna draw 64 lines swap d0 ;; in upper word move.w #64,d0 ;; and 64 pixels each move.l d0,B_COUNT move.l #$00040000,B_IINC ;; shade value for source move.l #SRCEN|DSTEN|UPDA1|UPDA2|SRCSHADE,B_CMD g) Blitting a 64x64 piece from a 128x128 pixmap (Pos: 10, 20) unto a 320x200 pixmap with source shading (Pos: 100,120). The pixmap will appear rotated about 45 degrees The source is at $30000 the destination at $20000. (TESTED) -------------------------------------------------------------- move.l #$20000,A1_BASE ;; point to destination move.l #PIXEL16|XADDINC|WID320|PITCH1,A1_FLAGS ;; note the WID320!! move.w #120,d0 ;; Y pos swap d0 ;; in upper word move.w #100,d0 ;; X pos in lower move.l d0,A1_PIXEL ;; start in the middle move.l #0,A1_INC ;; scaling in the X direction move.w #$8000,d0 ;; and stepping diagonally swap d0 move.w #$8000,d0 move.l d0,A1_FINC move.w #-33,d0 swap d0 move.w #-32,d0 move.l d0,A1_STEP move.w #$8000,d0 swap d0 move.w #$8000,d0 move.l d0,A1_FSTEP move.l #$30000,A2_BASE move.l #PIXEL16|XADDPIX|WID128|PITCH1,A2_FLAGS move.w #12,d0 ;; Y pos swap d0 ;; in upper word move.w #10,d0 ;; X pos in lower move.l d0,A2_PIXEL move.w #1,d0 swap d0 move.w #-64,d0 move.l d0,A2_STEP move.w #64,d0 ;; we wanna draw 64 lines swap d0 ;; in upper word move.w #64,d0 ;; and 64 pixels each move.l d0,B_COUNT move.l #$00040000,B_IINC ;; shade value for source move.l #LFU_REPLACE|DSTEN|SRCEN|UPDA1|UPDA1F|UPDA2|SRCSHADE,B_CMD Rotating with the blitter: =-=-=-=-=-=-=-=-=-=-=-=-= Scaling and rotation are really nice effects you can do with the blitter. But you got to be careful that you don't leave holes accidentally on the screen. There are two ways to produce holes, one because of using a step size (in either direction) that is larger than 1. This should be obvious I guess. The other not so obvious source of holes are quantization errors. For example to rotate a bitmap around 30 degrees, you might do these calculations: a A +--------+ B our source pixmap of size 64x64 | | | | a a == 64 | | D +--------+ C A x ........+......... That's how it should look like / \ . rotated / \ . y / \. D + + B \ / a \ / a \ / + C A x +........... a magnified look at the upper corner \m) 90 . we notice that: \ . \ . \ . x = cos( m) * a \ . y y = sin( m) * a a \ . \ . \ . m = 30 deg \ . x = 55.43 = $0037.6CF5 \. y = 32.00 = $0020.0000 + B hor increment = x / a = cos( m) = 0.87 = $0.DDB4 ($1.0000 * 0.87) ver increment = y / a = sin( m) = 0.50 = $0.8000 Y X --------+-----+-----+ A1_INC 0 0 A1_FINC $8000 $DDB4 We wanna draw in runs from A to B. Now after a line has been drawn. We need to step back to the point we came from (A) (-55.43,-32) and then move in a 60 degree (180 - 90 - 30) angle backwards (-) and downwards (+), down the left slope (A -> D). To get it perfect we calculate everything in integer fractional representation (like the Blitter does): Y X 64 * A1_INC.A1_FINC = $20.0000 $37.6D00 hor step = -x - cos( 60) = -$37.6D00 - $8000 = $FFC81300 ver step = -y + sin( 60) = -$20.0000 + $DDB4 = $FFE0DDB4 Y X --------+-----+-----+ A1_STEP $FFE0 $FFC8 A1_FSTEP $DDB4 $1300 Now if you blit something on the screen you'll see holes (not drawn pixels) in your pixmap, although the step size in both directions is 1 (sin(x)^2 + cos(x)^2 = 1). The error is introduced while the blitter is stepping in the 'integer.fractional' domain and then plots a pixel in the 'integer' domain. What I mean with 'integer.fractional' domain are the contents of the A1_PIXEL, A1_FPIXEL and the A1_FPIXEL and the A1_INC, A1_FINC registers. The problem will be visible on adjacent lines only, because the quantization of the pixels, which starts at a different fractional offset, will be slightly but decisively different for the subsequent runs. Try the following program. Run it once with BLOCK set to 1 and look at the resulting moiree pattern. Now set BLOCK to 0 and examine the colored lines closely (drawn in sequence from top to bottom) and notice how each line differs from the next. BLOCK equ 1 .if BLOCK HEIGHT equ 64 WIDTH equ 64 .else HEIGHT equ 16 WIDTH equ 16 .endif HINC equ $DDB4 VINC equ $8000 HSTEP equ -(HEIGHT*HINC)-VINC VSTEP equ -(WIDTH*VINC)+HINC blit: .wait: move.l B_CMD,d0 lsr.w #1,d0 bcc.b .wait move.l #$20000,A1_BASE ;; point to destination move.l #PIXEL16|XADDINC|WID256|PITCH1,A1_FLAGS ;; note the WID320 move.w #64,d0 ;; Y pos swap d0 ;; in upper word move.w #128,d0 ;; X pos in lower move.l d0,A1_PIXEL ;; start in the middle move.l #$0,A1_FPIXEL move.l #$0,A1_INC move.w #VINC,d0 swap d0 move.w #HINC,d0 move.l d0,A1_FINC .if BLOCK move.w #VSTEP>>16,d0 .else move.w #(VSTEP>>16)+2,d0 ;; uncomment this, comment out next .endif swap d0 move.w #HSTEP>>16,d0 move.l d0,A1_STEP move.w #VSTEP&$FFFF,d0 swap d0 move.w #HSTEP&$FFFF,d0 move.l d0,A1_FSTEP move.w #HEIGHT,d0 ;; we wanna draw # lines swap d0 ;; in upper word move.w #WIDTH,d0 ;; and # pixels each move.l d0,B_COUNT .if BLOCK move.l #PATDSEL|UPDA1|UPDA1F|LFU_REPLACE,B_CMD .else move.l #$01000000,B_IINC move.l #$00C0,B_PATD move.l #GOURD|TOPBEN|PATDSEL|UPDA1|UPDA1F|LFU_REPLACE,B_CMD .endif rts How do you get rid of the holes ? If you want to use the blitter for rotation, you probably should scale down the bitmaps you want to rotate. Maybe using a 96x96 source pixmap for a 'apparent' 64x64 target pixmap size will be sufficient. You gotta experiment. It depends on the rotation angle! ( Well there's a software method I did once, which can do rotation without holes. It goes basically like this: Use the steepest slope for "STEP" use the other slope for your line drawings (like Bresenham f.e.) Use the most outside pixel as your starting pixel Draw a line with the required slope. Do an integer step horizontally (or vertically but not both) away from your first starting pixel. Skip as many pixels as needed until you want to start drawing. Draw the line. I can't quite see this being done with the blitter though :). )