Difference between revisions of "Snippet:Blit"

From veswiki
Jump to: navigation, search
m (1 revision)
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
The '''blit''' subroutine reads a two-color (1 bit per pixel) block of graphics data from ROM and displays it on the screen, using several parameters. It works much in the same way as the drawchar routine except for arbitrarily sized data. The code was originally taken from [[Disassembly:Videocart_26|Videocart 26]] and adapted to be more flexible and reusable.
+
The '''blit''' subroutine reads a two-color (1 bit per pixel) block of graphics data from ROM and displays it on the screen, using several parameters. It works much in the same way as the BIOS drawchar routine except for arbitrarily sized data. The code was originally taken from [[Disassembly:Videocart_26|Videocart 26]] and adapted to be more flexible and reusable.
  
 
The routine is separated into two parts, '''blitGraphic''' and '''blit'''. '''blit''' takes parameters in registers r1-r6, and retrieves graphics data from the location DC0 points to. It can be called independently of '''blitGraphic'''. '''blitGraphic''' takes hard-coded parameters from ROM at the address pointed at by DC0 and then calls the '''blit''' routine. When the parameters do not need to be dynamic, storing the parameters in ROM and calling the '''blitGraphic''' routine directly can be more efficient than writing them to the registers and calling '''blit'''.
 
The routine is separated into two parts, '''blitGraphic''' and '''blit'''. '''blit''' takes parameters in registers r1-r6, and retrieves graphics data from the location DC0 points to. It can be called independently of '''blitGraphic'''. '''blitGraphic''' takes hard-coded parameters from ROM at the address pointed at by DC0 and then calls the '''blit''' routine. When the parameters do not need to be dynamic, storing the parameters in ROM and calling the '''blitGraphic''' routine directly can be more efficient than writing them to the registers and calling '''blit'''.
 +
 +
Note that coordinate (0,0) is usually outside the visible emulation area, in MESS/MESSUI/MAME visible area starts at (4,4).
 +
 +
Code works with the '''DASM''' compiler.
 +
 +
'''Tip:''' If you want a block in one color, set both colors the same and skip setting the data pointer (DC0).
  
 
<pre>
 
<pre>
Line 28: Line 34:
 
; load the graphics address
 
; load the graphics address
 
lm
 
lm
lr Qu, A ; into Q
+
lr QU, A ; storea data address in Q, one byte at the time
 
lm
 
lm
lr Ql, A
+
lr QL, A
lr DC, Q ; load it into the DC
+
lr DC, Q ; copy Q into DC0
  
; call the blit function
+
; continue with the blit function
jmp blit
 
  
 
;---------------;
 
;---------------;
Line 48: Line 53:
 
; register reference:
 
; register reference:
 
; -------------------
 
; -------------------
; r1 = color 1 (off)
+
; r1 = color 0 (off) (alias: clear/bkg/blue/red/green)
; r2 = color 2 (on)
+
; r2 = color 1 (on)  (alias: clear/bkg/blue/red/green)
 
; r3 = x position
 
; r3 = x position
 
; r4 = y position
 
; r4 = y position
Line 62: Line 67:
  
 
blit:
 
blit:
; fix the x coordinate
 
lis 4
 
as 3
 
lr 3, A
 
; fix the y coordinate
 
lis 4
 
as 4
 
lr 4, A
 
 
 
lis 1
 
lis 1
 
lr 9, A ; load #1 into r9 so it'll be reset when we start
 
lr 9, A ; load #1 into r9 so it'll be reset when we start
Line 116: Line 112:
 
outs 1 ; output A in p1 (color)
 
outs 1 ; output A in p1 (color)
  
.blitTransferData:
+
blit.transferData:
; transfer the pixel data
+
lis 6 ; transfer the pixel data
li $60
+
sl 4
 
outs 0
 
outs 0
li $c0
+
sl 1
 
outs 0
 
outs 0
; and delay a little bit
+
 
.blitSavePixelDelay:
+
lis 4
ai $60 ; add 96
+
blit.savePixelDelay:
bnz .blitSavePixelDelay ; loop if not 0 (small delay)
+
ai $ff
 +
bnz blit.savePixelDelay
 +
 
  
 
.blitCheckColumn:
 
.blitCheckColumn:
Line 143: Line 141:
 
; return from the subroutine
 
; return from the subroutine
 
pop
 
pop
 +
 
</pre>
 
</pre>
  
<em>Note: the adjustment of x and y in '''blit''' are to allow the coodinates 0, 0 to access the upper left pixel </em>visible to the screen<em>, not to VRAM, which expands four pixels above and to the left of that pixel.</em>
 
  
 
To call the above functions, you should use:
 
To call the above functions, you should use:
Line 154: Line 152:
 
</pre>
 
</pre>
  
for '''blitGraphic''', and:
+
for '''blitGraphic''', and
  
 
<pre>
 
<pre>
; parameters have been loaded into r1-r6 beforehand
+
; when parameters have been loaded into r1-r6 beforehand
 
dci graphic.data ; address of graphic data
 
dci graphic.data ; address of graphic data
 
pi blit
 
pi blit
Line 166: Line 164:
 
<pre>
 
<pre>
 
graphic.parameters:
 
graphic.parameters:
.byte bkg ; color 1
+
.byte bkg ; color 0
.byte blue ; color 2
+
.byte blue ; color 1
 
.byte 4 ; x position
 
.byte 4 ; x position
 
.byte 18 ; y position
 
.byte 18 ; y position

Latest revision as of 14:57, 21 June 2026

The blit subroutine reads a two-color (1 bit per pixel) block of graphics data from ROM and displays it on the screen, using several parameters. It works much in the same way as the BIOS drawchar routine except for arbitrarily sized data. The code was originally taken from Videocart 26 and adapted to be more flexible and reusable.

The routine is separated into two parts, blitGraphic and blit. blit takes parameters in registers r1-r6, and retrieves graphics data from the location DC0 points to. It can be called independently of blitGraphic. blitGraphic takes hard-coded parameters from ROM at the address pointed at by DC0 and then calls the blit routine. When the parameters do not need to be dynamic, storing the parameters in ROM and calling the blitGraphic routine directly can be more efficient than writing them to the registers and calling blit.

Note that coordinate (0,0) is usually outside the visible emulation area, in MESS/MESSUI/MAME visible area starts at (4,4).

Code works with the DASM compiler.

Tip: If you want a block in one color, set both colors the same and skip setting the data pointer (DC0).

;===========;
; Blit Code ;
;===========;

;--------------;
; Blit Graphic ;
;--------------;

; takes graphic parameters from ROM, stores them in r1-r6, 
; changes the DC and calls the blit function with the parameters
;
; modifies: r1-r6, Q, DC

blitGraphic:
	; load six bytes from the parameters into r0-r5
	lisu	0
	lisl	1
.blitGraphicGetParms:
	lm   
	lr	I, A						; store byte and increase ISAR
	br7	.blitGraphicGetParms				; not finished with the registers, loop

	; load the graphics address
	lm
	lr	QU, A						; storea data address in Q, one byte at the time
	lm
	lr	QL, A
	lr	DC, Q						; copy Q into DC0

	; continue with the blit function

;---------------;
; Blit Function ;
;---------------;

; this function blits a graphic based on parameters set in r1-r6,
; and the graphic data pointed to by DC0, onto the screen
; originally from cart 26, modified and annotated
;
; modifies: r1-r9, DC

; register reference:
; -------------------
; r1 = color 0 (off) (alias: clear/bkg/blue/red/green)
; r2 = color 1 (on)  (alias: clear/bkg/blue/red/green)
; r3 = x position
; r4 = y position
; r5 = width
; r6 = height (and vertical counter)
;
; r7 = horizontal counter
; r8 = graphics byte
; r9 = bit counter
;
; DC = pointer to graphics

blit:
	lis	1
	lr	9, A						; load #1 into r9 so it'll be reset when we start
	lr	A, 4						; load the y offset
	com							; invert it
.blitRow:
	outs	5						; load accumulator into port 5 (row)

	; check vertical counter
	ds	6						; decrease r6 (vertical counter)
	bnc	.blitExit					; if it rolls over exit

	; load the width into the horizontal counter
	lr	A, 5
	lr	7, A

	lr	A, 3						; load the x position
	com							; complement it
.blitColumn:
	outs	4						; use the accumulator as our initial column
	; check to see if this byte is finished
	ds	9						; decrease r9 (bit counter)
	bnz	.blitDrawBit					; if we aren't done with this byte, branch

.blitGetByte:
	; get the next graphics byte and set related registers
	lis	8
	lr	9, A						; load #8 into r9 (bit counter)
	lm
	lr	8, A						; load a graphics byte into r8

.blitDrawBit:
	; shift graphics byte
	lr	A, 8						; load r8 (graphics byte)
	as	8						; shift left one (with carry)
	lr	8, A						; save it

	; check color to use
	lr	A, 2						; load color 1
	bc	.blitSavePixel					; if this bit is on, draw the color
	lr	A, 1						; load color 2
.blitSavePixel:
	inc
	bc	.blitCheckColumn				; branch if the color is "clear"
	outs	1						; output A in p1 (color)

blit.transferData:
	lis	6						; transfer the pixel data
	sl	4
	outs	0
	sl	1
	outs	0

	lis	4
blit.savePixelDelay:
	ai	$ff
	bnz	blit.savePixelDelay


.blitCheckColumn:
	ds	7						; decrease r7 (horizontal counter)
	bz	.blitCheckRow					; if it's 0, branch

	ins	4						; get p4 (column)
	ai	$ff						; add 1 (complemented)
	br	.blitColumn					; branch

.blitCheckRow:
	ins	5						; get p5 (row)
	ai	$ff						; add 1 (complemented)
	br	.blitRow					; branch

.blitExit:
	; return from the subroutine
	pop


To call the above functions, you should use:

	dci	graphic.parameters	; address of parameters
	pi	blitGraphic

for blitGraphic, and

	; when parameters have been loaded into r1-r6 beforehand
	dci	graphic.data		; address of graphic data
	pi	blit

for blit. If you're using parameters stored in ROM, they should be in this order:

graphic.parameters:
	.byte	bkg			; color 0
	.byte	blue			; color 1
	.byte	4			; x position
	.byte	18			; y position
	.byte	$60			; width
	.byte	$13			; height
	.word	graphic.data		; address for the graphics

See Also