 AREA	plotters, CODE ; Not strictly true, but we want the important
		       ; variables kept together with the code so we
		       ; don't have to use long ADRs or LDRs

 GET    Hdr.Macros
 GET    Asm:SWInames.h

 EXPORT Popcorn_ReadScreenDetails, Popcorn_SwapBanks
 EXPORT Popcorn_PlotSprite, Popcorn_PlotBackdrop
 EXPORT Popcorn_SetClipWindow, Popcorn_ClearScreen

 EXPORT plot_window
 EXPORT Popcorn_PlotSpriteNoBounds, Popcorn_PlotPoint

in_buffer1	& 148,149,11,12,7,4,5,-1
screen_number	& 0 ; 0 or 1 depending on animation frame
screen_start	& 0 ; Base of screen bank to start plotting on
screen_reserve	& 0 ; Base of screen bank being displayed
screen_lastxpix	& 0 ; No. of columns on screen
screen_lastypix & 0 ; No. of rows on screen
screen_size	& 0 ; Size of one screen bank

plot_window
screen_clip_left	& 0
screen_clip_top		& 0
screen_clip_right	& 0
screen_clip_bottom 	& 0

no_shadow	& 0
		DCB "No shadow screen memory found.",0

 ALIGN

Popcorn_ReadScreenDetails
;
; Self-explanatory routine which reads in a few VDU variables and
; stores them internally for the sprite plotter and other display
; routines
;
;	STMFD	R13!,{R0-R2,R14}
	MOV	R0,#112
	MOV	R1,#2
	STR	R1,screen_number
	SWI	OS_Byte
	MOV	R0,#113
	MOV	R1,#1
	SWI	OS_Byte
	ADR	R0,in_buffer1
	ADR	R1,screen_start
	SWI	OS_ReadVduVariables
	LDR	R1,screen_lastxpix
	LDR	R2,screen_lastypix
	STR	R1,screen_clip_right
	STR	R2,screen_clip_bottom
	MOV	R2,#0
	STR	R2,screen_clip_top
	STR	R2,screen_clip_left
	LDR	R0,screen_start
	LDR	R1,screen_reserve
	CMP	R0,R1
	ADREQ	R0,no_shadow
	SWIEQ	OS_GenerateError
	MOVS    pc,lr
;	LDMFD	R13!,{R0-R2,PC}^

Popcorn_SwapBanks
;
; Another fairly simple routine...
;
;	STMFD	R13!,{R0-R2,R14}
	LDR	R0,screen_start
	LDR	R1,screen_reserve
	STR	R1,screen_start
	STR	R0,screen_reserve

	LDR	R1,screen_number
	RSB	R1,R1,#3
	STR	R1,screen_number
	MOV	R0,#112
	SWI	OS_Byte
	MOV	R0,#113
	SWI	OS_Byte
	MOVS    pc,lr
;	LDMFD	R13!,{R0-R2,PC}^

Popcorn_ClearScreen
;
; Fills the screen memory as quickly as possible with a particular
; byte, specified in R0.  It's fast anyway.
;
	STMFD	R13!,{R4-R12,R14}
	AND	R0,R0,R0,LSL#8
	AND	R0,R0,R0,LSL#16
	MOV	R1,R0
	MOV	R2,R0
	MOV	R3,R0
	MOV	R4,R0
	MOV	R5,R0
	MOV	R6,R0
	MOV	R7,R0
	MOV	R8,R0
	MOV	R9,R0
	MOV	R10,R0
	MOV	R11,R0
	LDR	R12,screen_start
	LDR	R14,screen_size
	SUB	R14,R14,#48
Popcorn_ClearScreen_loop
	STMIA	R12!,{R0-R11} ; Store 48 bytes at a time
	SUBS	R14,R14,#48
	BGT	Popcorn_ClearScreen_loop
	ADD	R14,R14,#48
	TST	R14,#32
	STMNEIA	R12!,{R0-R7}  ; Then carry on in decreasing powers of two
	TST	R14,#16
	STMNEIA	R12!,{R0-R3}
	TST	R4,#8
	STMNEIA	R12!,{R0-R1}
	TST	R4,#4
	STRNE	R0,[R12],#4
	TST	R4,#2
	STRNEB	R0,[R12],#1
	STRNEB	R0,[R12],#1
	TST	R4,#1
	STRNEB	R0,[R12],#1
	LDMFD	R13!,{R4-R12,PC}^

Popcorn_PlotBackdrop
;
; Enter with R0 > backdrop data; similar to above routine
;
	STMFD	R13!,{R4-R12,R14}
	LDR	R12,screen_start
	LDR	R14,screen_size
	MOV	R11,R0
	SUBS	R14,R14,#44
Popcorn_PlotBackdrop_loop
	LDMIA	R11!,{R0-R10}
	STMIA	R12!,{R0-R10}
	SUBS	R14,R14,#44
	BGT	Popcorn_PlotBackdrop_loop
	ADD	R14,R14,#44
	TST	R14,#32
	LDMNEIA	R11!,{R0-R7}
	STMNEIA	R12!,{R0-R7}
	TST	R14,#16
	LDMNEIA	R11!,{R0-R3}
	STMNEIA	R12!,{R0-R3}
	TST	R4,#8
	LDMNEIA	R11!,{R0-R1}
	STMEQIA	R12!,{R0-R1}
	TST	R4,#4
	LDRNE	R0,[R11],#4
	STRNE	R0,[R12],#4
	TST	R4,#2
	LDRNEB	R0,[R11],#1
	STRNEB	R0,[R12],#1
	LDRNEB	R0,[R11],#1
	STRNEB	R0,[R12],#1
	TST	R4,#1
	LDRNEB	R0,[R11],#1
	STRNEB	R0,[R12],#1
	LDMFD	R13!,{R4-R12,PC}

Popcorn_SetClipWindow
	STR	R0,screen_clip_left
	STR	R1,screen_clip_top
	STR	R2,screen_clip_right
	STR	R3,screen_clip_bottom
	MOVS    pc,lr

; plots a single dot in specified colour
; entry: r0 = x
;        r1 = y
;        r2 = colour
; exit:  none
Popcorn_PlotPoint
        ; check point coords against plot window
        LDR     r3,screen_clip_top
        CMP     r1,r3
        MOVLTS  pc,lr
        LDR     r3,screen_clip_bottom
        CMP     r1,r3
        MOVGTS  pc,lr

        LDR	r3,screen_clip_left
        CMP     r0,r3
        MOVLTS  pc,lr
        LDR	r3,screen_clip_right
        CMP     r0,r3
        MOVGTS  pc,lr

	; we know it's in the plot window, so just plot and go
        LDR     ip,screen_lastxpix
        ADD     ip,ip,#1                ; screen x size
        MLA     r3,ip,r1,r0             ; r3 = y * xsize + x
        LDR     ip,screen_start
        ADD     ip,ip,r3
        STRB    r2,[ip]                 ; plot point
        MOVS    pc,lr

Popcorn_PlotSprite
;
; Enter with R0 > sprite data, format as described in magazine
;	     R1 = x counting right from 0 (left)
;	     R2 = y counting down from 0 (top)
;
	CMP	R0,#0
	MOVEQ	PC,R14
	STMFD	R13!,{R4-R12,R14}
;
; First thing we need to do is decide if we're totally off
;
	LDR	R3,[R0,#0]	; Width of sprite
	LDR	R4,[R0,#4]	; Height of sprite
	ADD	R3,R3,#1
	ADD	R4,R4,#1
	ADD	R3,R3,R1	; R3 = furthest right pixel to be plotted
	ADD	R4,R4,R2	; R4 = lowest pixel to be plotted
	LDR	R5,screen_clip_bottom
	LDR	R6,screen_clip_top
	LDR	R7,screen_clip_left
	LDR	R8,screen_clip_right
	CMP	R1,R8
	LDMGTFD	R13!,{R4-R12,PC}^	; Off right?
	CMP	R2,R5
	LDMGTFD	R13!,{R4-R12,PC}^	; Off bottom?
	CMP	R3,R7
	LDMLTFD	R13!,{R4-R12,PC}^	; Off left?
	CMP	R4,R6
	LDMLTFD	R13!,{R4-R12,PC}^	; Off top?

	STR	R4,last_y		; Store for later
	STR	R1,first_x		; likewise
;
; Now we know we have a sprite which is at least partially on screen,
; we need to find the first byte to start plotting at on the fisrt
; scan line
;
; Start = screen base address + x position + (y position * line length)
;
	LDR	R3,screen_start
	LDR	R4,screen_lastxpix
	ADD	R4,R4,#1
	MLA	R11,R2,R4,R3
	ADD	R11,R11,R1
; So now we'll keep R11 as our 'plot here' register

; We now need to find out where to start looking for our scan-line data
; which is determined by which image copy we choose, which is
; determined by what alignment we want.  See? :-)
;
	ADD	R10,R0,#8
	AND	R4,R1,#3		; R4 = alignment
	ADD	R10,R10,R4,LSL#2
	LDR	R10,[R10]
	ADD	R10,R10,R0		; R10 > start of scan-line data ptrs
	STR	R10,next_scan_line_ptr
;
; We've now got the 'from' and 'to' addresses, so start plotting lines now
; Quick list of registers to keep hold of : R10 > next scan-line data ptr
;					    R11 > next screen address
;					    R12 > next scan-line data
;
	B	first_scan_line		; Skip bit to increase counters
next_scan_line
	ADD	R2,R2,#1
	LDR	R3,last_y
	CMP	R2,R3			; Check we've not finished
	BEQ	finished_plot
	LDR	R11,next_scan_line_address ; Move R11 to next scan line
first_scan_line				; Registers already set up!
;
; First thing to do is work out where the start of the next scan line
; should be to avoid messy calculations later
;
	LDR	R3,screen_lastxpix
	ADD	R3,R3,#1
	ADD	R3,R3,R11
	STR	R3,next_scan_line_address
;
;
; First thing to check for is y clipping; if we're not on top or bottom,
; there's no point in going any further
;
	LDR	R3,screen_clip_bottom
	CMP	R2,R3
	BGT	finished_plot		; Finished if we're off the bottom
	LDR	R3,screen_clip_top
	CMP	R2,R3
	ADDLT	R10,R10,#4
	BLT	next_scan_line		; Try next line if we're off the top
;
; Right, now we know we have a scan line which is in the plot window
; in the y direction anyway, so we must have something to plot, so get
; the start of the scan line data
;

;
; Fetch the address of the first part of the scan line into R12
; and move R10 along
;
	LDR	R1,first_x		; Reset R1 to start of line
	LDR	R12,[R10],#4
	ADD	R12,R12,R0		; Get scan line ptr into R12
next_scan_line_bit
	LDR	R9,[R12],#4		; Get action code into R9
	MOV	R8,R9,LSR#24		; R8 = action
	BIC	R9,R9,#&FF000000	; R9 = number of bytes
;
; Now take some action on R8, or rather just check if it is zero
;
	CMP	R8,#2
	BGT	next_scan_line_bit
	CMP	R8,#0
	BEQ	next_scan_line
; Otherwise work out R5 and carry on
	ADD	R5,R1,R9		; R5 = x position after plot
;
; We have the positions of the first and last bytes of the 'bit', now
; work out whether the 'bit' is fully on-screen, or whether we need
; to do some X clipping
;
	LDR	R3,screen_clip_left
	LDR	R4,screen_clip_right
	CMP	R1,R3
	BLT	clip_left
	CMP	R5,R4
	BGT	clip_right
	B	no_clipping
;
; Relevant registers for X clipping -- pay attention to this
;
; R1  = x co-ordinate to start plotting (could be off screen?)
; R2  = y co-ordinate to start plotting
; R3  = first x pixel in window
; R4  = last x pixel in window
; R5  = x co-ordinate after plot (off screen?)
; R8  = 'type' part of type word (i.e. tt)
; R9  = number of bytes (i.e. dddd)
; R11 = screen address to start
; R12 = start address of sprite data
;
clip_left
	CMP	R8,#2
	BNE	clip_left_bit_on
	ADD	R11,R11,R9
	MOV	R1,R5
	B	next_scan_line_bit	; Deal with masks by just shifting
					; the relevant pointers on
clip_left_bit_on
	CMP	R5,R3
	BGE	clip_left_not_completely_off
	AND	R7,R11,#3
	ADD	R12,R12,R7		; Push R12 along according to align
	ADD	R12,R12,R9
	ADD	R11,R11,R9
	MOV	R1,R5
	B	align_r12_no_restore
clip_left_not_completely_off
	AND	R7,R11,#3
	ADD	R12,R12,R7		; Push R12 along according to align
	SUB	R6,R3,R1		; R6 = no. of pixels off left
	ADD	R11,R11,R6
	ADD	R12,R12,R6
	MOV	R1,R5
	SUB	R9,R9,R6		; Adjust start / no. of pixels
	CMP	R5,R4			; Check for clip right as well
	BLE	start_plot_bit
	ADD	R4,R4,#1		;
	SUB	R6,R5,R4		; Code copied from below
	STR	R6,compensate_right	;
	SUB	R9,R9,R6		;
	B	start_plot_bit		;

clip_right
	CMP	R8,#2
	BEQ	next_scan_line		; Mask off right -> next line
	ADD	R4,R4,#1		; Arse
	SUB	R6,R5,R4		; R6 = no. of pixels off right
	STR	R6,compensate_right	; Compensate after plot
	SUB	R9,R9,R6		; Clip pixels off right
	MOV	R1,R5
	AND	R3,R11,#3
	ADD	R12,R12,R3
	B	start_plot_bit

no_clipping
	ADD	R1,R1,R9		; Adjust X
	CMP	R8,#2
	ADDEQ	R11,R11,R9
	BEQ	next_scan_line_bit	; Skip screen memory if it's a mask
	AND	R3,R11,#3		; Get alignment of screen address
	ADD	R12,R12,R3		; Adjust start of data
;
; Right, here is where we can start plotting!
;   R12 > sprite data (aligned, so watch for zeroes at start)
;   R11 > screen memory to start (adjusted for clipping)
;   R9  = number of bytes to plot
;
start_plot_bit
	STMFD	R13!,{R0-R7}		; Keep scratch registers
					; 'cos we're going to overwrite them
					; with multiple loads/stores
;
; Plot 0-3 bytes so we start on a word boundary
;
	CMP	R9,#0
	BLE	align_r12
	TST	R11,#1
	BEQ	no_align_0
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	align_r12
no_align_0
	TST	R11,#2
	BEQ	no_align_1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	align_r12
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	align_r12
no_align_1

;
; Now we're on a word boundary, we can start plotting big chunks with
; LDR and LDM instructions
;
	TST	R9,#2_100
	BEQ	no_bit_2
	LDR	R0,[R12],#4
	STR	R0,[R11],#4
	BICS	R0,R9,#2_111
	BEQ	no_bit_8
no_bit_2
	TST	R9,#2_1000
	BEQ	no_bit_3
	LDMIA	R12!,{R0-R1}
	STMIA	R11!,{R0-R1}
no_bit_3
	TST	R9,#2_10000
	BEQ	no_bit_4
	LDMIA	R12!,{R0-R3}
	STMIA	R11!,{R0-R3}
no_bit_4
	TST	R9,#2_100000
	BEQ	no_bit_5
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
no_bit_5
	TST	R9,#2_1000000
	BEQ	no_bit_6
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
no_bit_6
	TST	R9,#2_10000000
	BEQ	no_bit_7
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
no_bit_7
	TST	R9,#2_100000000
	BEQ	no_bit_8
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
no_bit_8
;
; Now we should have plotted all but the last 0-3 bytes
;
	TST	R9,#2_1
	BEQ	no_bit_0
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
no_bit_0
	TST	R9,#2_10
	BEQ	no_bit_1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
no_bit_1
;
; Now we need to align R12 so that it points to the next 'type' word,
; since it could be straggling at a non word-aligned position.
;
align_r12
	LDMFD	R13!,{R0-R7}		; Restore scratch registers
align_r12_no_restore
	LDR	R3,compensate_right
	ADD	R12,R12,R3
	MOV	R3,#0
	STR	R3,compensate_right
	ADD	R12,R12,#3
	BIC	R12,R12,#3
no_align
	B	next_scan_line_bit
finished_plot
	LDMFD	R13!,{R4-R12,PC}^

; added by rik - doesn't check any bounds at all, use with care
Popcorn_PlotSpriteNoBounds
;
; Enter with R0 > sprite data, format as described in magazine
;	     R1 = x counting right from 0 (left)
;	     R2 = y counting down from 0 (top)
;
	CMP	R0,#0
	MOVEQ	PC,R14
	STMFD	R13!,{R4-R12,R14}
;
; First thing we need to do is decide if we're totally off
;
	LDR	R3,[R0,#0]	; Width of sprite
	LDR	R4,[R0,#4]	; Height of sprite
	ADD	R3,R3,#1
	ADD	R4,R4,#1
	ADD	R3,R3,R1	; R3 = furthest right pixel to be plotted
	ADD	R4,R4,R2	; R4 = lowest pixel to be plotted

	STR	R4,last_y		; Store for later
	STR	R1,first_x		; likewise
;
; Now we know we have a sprite which is at least partially on screen,
; we need to find the first byte to start plotting at on the fisrt
; scan line
;
; Start = screen base address + x position + (y position * line length)
;
	LDR	R3,screen_start
	LDR	R4,screen_lastxpix
	ADD	R4,R4,#1
	MLA	R11,R2,R4,R3
	ADD	R11,R11,R1
; So now we'll keep R11 as our 'plot here' register

; We now need to find out where to start looking for our scan-line data
; which is determined by which image copy we choose, which is
; determined by what alignment we want.  See? :-)
;
	ADD	R10,R0,#8
	AND	R4,R1,#3		; R4 = alignment
	ADD	R10,R10,R4,LSL#2
	LDR	R10,[R10]
	ADD	R10,R10,R0		; R10 > start of scan-line data ptrs
	STR	R10,next_scan_line_ptr
;
; We've now got the 'from' and 'to' addresses, so start plotting lines now
; Quick list of registers to keep hold of : R10 > next scan-line data ptr
;					    R11 > next screen address
;					    R12 > next scan-line data
;
	B	NB_first_scan_line	; Skip bit to increase counters
NB_next_scan_line
	ADD	R2,R2,#1
	LDR	R3,last_y
	CMP	R2,R3			; Check we've not finished
	BEQ	NB_finished_plot
	LDR	R11,next_scan_line_address ; Move R11 to next scan line
NB_first_scan_line				; Registers already set up!
;
; First thing to do is work out where the start of the next scan line
; should be to avoid messy calculations later
;
	LDR	R3,screen_lastxpix
	ADD	R3,R3,#1
	ADD	R3,R3,R11
	STR	R3,next_scan_line_address
;
; Fetch the address of the first part of the scan line into R12
; and move R10 along
;
	LDR	R1,first_x		; Reset R1 to start of line
	LDR	R12,[R10],#4
	ADD	R12,R12,R0		; Get scan line ptr into R12
NB_next_scan_line_bit
	LDR	R9,[R12],#4		; Get action code into R9
	MOV	R8,R9,LSR#24		; R8 = action
	BIC	R9,R9,#&FF000000	; R9 = number of bytes
;
; Now take some action on R8, or rather just check if it is zero
;
	CMP	R8,#2
	BGT	NB_next_scan_line_bit
	CMP	R8,#0
	BEQ	NB_next_scan_line
; Otherwise work out R5 and carry on
	ADD	R5,R1,R9		; R5 = x position after plot

;
; Relevant registers for X clipping -- pay attention to this
;
; R1  = x co-ordinate to start plotting (could be off screen?)
; R2  = y co-ordinate to start plotting
; R3  = first x pixel in window
; R4  = last x pixel in window
; R5  = x co-ordinate after plot (off screen?)
; R8  = 'type' part of type word (i.e. tt)
; R9  = number of bytes (i.e. dddd)
; R11 = screen address to start
; R12 = start address of sprite data
;
	ADD	R1,R1,R9		; Adjust X
	CMP	R8,#2
	ADDEQ	R11,R11,R9
	BEQ	NB_next_scan_line_bit	; Skip screen memory if it's a mask
	AND	R3,R11,#3		; Get alignment of screen address
	ADD	R12,R12,R3		; Adjust start of data
;
; Right, here is where we can start plotting!
;   R12 > sprite data (aligned, so watch for zeroes at start)
;   R11 > screen memory to start (adjusted for clipping)
;   R9  = number of bytes to plot
;
NB_start_plot_bit
	STMFD	R13!,{R0-R7}		; Keep scratch registers
					; 'cos we're going to overwrite them
					; with multiple loads/stores
;
; Plot 0-3 bytes so we start on a word boundary
;
	CMP	R9,#0
	BLE	NB_align_r12
	TST	R11,#1
	BEQ	NB_no_align_0
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	NB_align_r12
NB_no_align_0
	TST	R11,#2
	BEQ	NB_no_align_1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	NB_align_r12
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	SUBS	R9,R9,#1
	BEQ	NB_align_r12
NB_no_align_1

;
; Now we're on a word boundary, we can start plotting big chunks with
; LDR and LDM instructions
;
	TST	R9,#2_100
	BEQ	NB_no_bit_2
	LDR	R0,[R12],#4
	STR	R0,[R11],#4
	BICS	R0,R9,#2_111
	BEQ	NB_no_bit_8
NB_no_bit_2
	TST	R9,#2_1000
	BEQ	NB_no_bit_3
	LDMIA	R12!,{R0-R1}
	STMIA	R11!,{R0-R1}
NB_no_bit_3
	TST	R9,#2_10000
	BEQ	NB_no_bit_4
	LDMIA	R12!,{R0-R3}
	STMIA	R11!,{R0-R3}
NB_no_bit_4
	TST	R9,#2_100000
	BEQ	NB_no_bit_5
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
NB_no_bit_5
	TST	R9,#2_1000000
	BEQ	NB_no_bit_6
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
NB_no_bit_6
	TST	R9,#2_10000000
	BEQ	NB_no_bit_7
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
NB_no_bit_7
	TST	R9,#2_100000000
	BEQ	NB_no_bit_8
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
	LDMIA	R12!,{R0-R7}
	STMIA	R11!,{R0-R7}
NB_no_bit_8
;
; Now we should have plotted all but the last 0-3 bytes
;
	TST	R9,#2_1
	BEQ	NB_no_bit_0
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
NB_no_bit_0
	TST	R9,#2_10
	BEQ	NB_no_bit_1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
	LDRB	R0,[R12],#1
	STRB	R0,[R11],#1
NB_no_bit_1
;
; Now we need to align R12 so that it points to the next 'type' word,
; since it could be straggling at a non word-aligned position.
;
NB_align_r12
	LDMFD	R13!,{R0-R7}		; Restore scratch registers
NB_align_r12_no_restore
	LDR	R3,compensate_right
	ADD	R12,R12,R3
	MOV	R3,#0
	STR	R3,compensate_right
	ADD	R12,R12,#3
	BIC	R12,R12,#3
NB_no_align
	B	NB_next_scan_line_bit
NB_finished_plot
	LDMFD	R13!,{R4-R12,PC}^

;
; This should never happen :-)
;
uh_oh
	ADR	R0,error
	SWI	OS_GenerateError

error	& 0
	DCB "Type word out of range (0-2)",0
	ALIGN

last_y			& 0
first_x			& 0
next_scan_line_address	& 0
next_scan_line_ptr	& 0
compensate_right	& 0

 END
