;
; draw.s
;
; Renders DrawFiles (MDW)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; Sapphire is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Sapphire.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

;----- External dependencies ------------------------------------------------

		GET	sapphire:divide
		GET	sapphire:mem
		GET	sapphire:msgs
		GET	sapphire:roVersion
		GET	sapphire:sapphire
		GET	sapphire:screen
		GET	sapphire:sprite

;----- Main code ------------------------------------------------------------

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- Register allocation ---
;
; R12 == pointer to font array
; R10 == pointer to transform matrix
;  R9 == pointer to clipping block (in Draw units)
;  R8 == pointer to end of objects to render
;  R7 == pointer to start of current object

; --- draw_render ---
;
; On entry:	R0 == scale to plot drawfile (16.16 form)
;		R1 == pointer to a redraw block
;		R2 == pointer to drawfile in memory
;		R3 == size of drawfile block
;
; On exit:	--
;
; Use:		Renders a DrawFile in a window.  Objects which aren't
;		recognised are not rendered.  The objects which are handled
;		are as follows:
;
;		* Font table objects
;		* Text objects (in fonts, or in system font)
;		* Draw path objects, filled and unfilled, including
;		  dotted outlines
;		* Group objects
;		* Tagged objects
;		* Sprite objects, rendered as well as we can make it
;		* Transformed text, only on RISC OS 3
;		* Transformed sprite, only on RISC OS 3

		EXPORT	draw_render
draw_render	ROUT

		STMFD	R13!,{R0-R12,R14}	;Save a load of registers

		; --- Set up the transformation matrix ---

		LDR	R4,[R1,#4]		;Load minimum x coord
		ADD	R14,R1,#16		;Point to maximum y coord
		LDMIA	R14,{R5-R7}		;Load y coord and scroll pos
		SUB	R4,R4,R6		;Work out x origin position
		SUB	R5,R5,R7		;And the y origin position

		SUB	R13,R13,#24		;Make way for the transform
		MOV	R10,R13			;Point to it nicely
		MOV	R14,R13			;Point to it for filling
		MOV	R6,R0			;Set up x scale from user
		MOV	R7,#0			;Don't do fancy x transforms
		MOV	R8,#0			;Don't do fancy y transforms
		MOV	R9,R0			;And scale y from user
		STMIA	R14!,{R6-R9}		;Save this in the block
		MOV	R6,R4,LSL #8		;Convert offset to draw units
		MOV	R7,R5,LSL #8		;And convert y offset too
		STMIA	R14,{R6,R7}		;Save these in the matrix too

		; --- Set up the adjusted clipping block too ---

		SUB	R13,R13,#16		;Make way for a clipping blk
		ADD	R14,R1,#28		;Point to original block
		LDMIA	R14,{R6-R9}		;Load the clipping coords
		SUB	R6,R6,R4		;Convert these to window...
		SUB	R7,R7,R5		;... coordinates for easy...
		SUB	R8,R8,R4		;... clipping
		SUB	R9,R9,R5
		MOV	R4,R0			;Get the scale factor safe

		; --- Now we have to divide by the scale factor ---

		MOV	R12,#&18000		;A useful constant (1 1/2)
		RSB	R0,R12,R6,LSL #16	;Take minimum x position
		MOV	R1,R4,LSR #8		;And the scale factor
		BL	divide			;Do the division
		MOV	R6,R0			;Take the result away nicely

		RSB	R0,R12,R7,LSL #16	;Take minimum y position
		MOV	R1,R4,LSR #8		;And the scale factor
		BL	divide			;Do the division
		MOV	R7,R0			;Take the result away nicely

		ADD	R0,R12,R8,LSL #16	;Take maximum x position
		MOV	R1,R4,LSR #8		;And the scale factor
		ADD	R0,R0,R1		;Make it round upwards
		BL	divide			;Do the division
		MOV	R8,R0			;Take the result away nicely

		ADD	R0,R12,R9,LSL #16	;Take maximum y position
		MOV	R1,R4,LSR #8		;And the scale factor
		ADD	R0,R0,R1		;Make it round upwards
		BL	divide			;Do the division
		MOV	R9,R0			;Take the result away nicely

		STMIA	R13,{R6-R9}		;Save the modified values
		MOV	R9,R13			;Point to the coords block

		; --- Set up start and end values ---

		MOV	R7,R2			;Get start address to render
		ADD	R8,R7,R3		;And calculate end address
		MOV	R0,R7			;Point to the drawfile
		BL	draw_checkValid	;Make sure the drawfile's OK
		BVS	%10draw_render		;If not don't draw it
		ADD	R7,R7,#40		;Point to renderable part

		; --- And finally initialise the font array ---

		SUB	R13,R13,#1024		;The font array is *big*
		MOV	R12,R13			;Point to it
		MOV	R0,R12			;Point to font array
		MOV	R1,#1024		;Get its size
		MOV	R2,#0			;We're going to fill it
		BL	mem_set			;So make it all zeroes

		; --- Do the main rendering and tidy up ---

		BL	draw__doRender		;And do the main job
10draw_render	ADD	R13,R10,#24		;Reclaim all the stack
		BL	draw__resetTextSize	;Make the text size sensible
		LDMFD	R13!,{R0-R12,PC}^	;Return to caller now

; --- draw_checkValid ---
;
; On entry:	R0 == pointer to start of drawfile
;
; On exit:	May return an error
;
; Use:		Checks whether a drawfile is basically sound.  This checking
;		isn't compulsory, and just checks the initial word and the
;		format version number -- nothing very exciting.

		EXPORT	draw_checkValid
draw_checkValid	ROUT

		BIC	R14,R14,#V_flag		;Assume everything's OK
		STMFD	R13!,{R1,R14}		;Save a register away
		LDR	R14,draw__drawMagic	;Load the magic word out
		LDR	R1,[R0,#0]		;Load the first word out
		CMP	R14,R1			;Do they match perfectly?
		BNE	%90draw_checkValid	;No -- then return error
		LDR	R14,[R0,#4]		;Load major format version
		CMP	R14,#201		;Is it old enough for me?
		LDMLEFD	R13!,{R1,PC}^		;Return to caller if OK

		; --- Version number is wrong ---

		ADR	R0,draw__tooNew		;Point to the error message
		B	%95draw_checkValid	;And handle the error

draw__drawMagic	DCB	"Draw"

draw__tooNew	DCD	1
		DCB	"drawTOONEW",0

		; --- It isn't a drawfile ---

90		ADR	R0,draw__badFile	;Point to the error message
95		BL	msgs_error		;Translate the error
		LDMFD	R13!,{R1,R14}		;Unstack some registers
		ORRS	PC,R14,#V_flag		;And return the error

draw__badFile	DCD	1
		DCB	"drawBADFILE",0

		LTORG

; --- draw__doRender ---
;
; On entry:	R7 == pointer to object to start rendering
;		R8 == pointer to first object not to render
;		R9 == pointer to coordinate clipping block
;		R10 == pointer to transformation matrix
;		R12 == pointer to font array
;
; On exit:	R7 points past last object rendered
;		R0-R6 may be corrupted
;
; Use:		Renders a group of objects.

draw__doRender	ROUT

		STMFD	R13!,{R14}		;Save a register
00		CMP	R7,R8			;Is there anything to do?
		BLLT	draw__renderObject	;Yes -- render an object
		BLT	%00draw__doRender	;And go round again
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- draw__renderObject ---
;
; On entry:	R7 == pointer to object to render
;		R8 == pointer to first object not to render
;		R9 == pointer to coordinate clipping block
;		R10 == pointer to transformation matrix
;		R12 == pointer to font array
;
; On exit:	R7 == pointer to next object to render
;		R0-R6 may be corrupted
;
; Use:		The main object rendering dispatch routine.

draw__renderObject ROUT

		LDR	R0,[R7,#0]		;Get the object's type
		CMP	R0,#(%10-%00)/4		;Is it in range of my table?
		ADDLO	PC,PC,R0,LSL #2		;Yes -- dispatch it then
		B	%10draw__renderObject	;Out of range -- ignore it

00		B	draw__readFontTable	;Font table object
		B	draw__renderText	;Render a text string
		B	draw__renderPath	;Render a standard draw path
		B	%10draw__renderObject	;Type 3 is not defined
		B	%10draw__renderObject	;Type 4 is not defined
		B	draw__renderSprite	;Render a sprite
		B	draw__renderGroup	;Handle a group of objects
		B	draw__renderTagged	;Render a tagged object
		B	%10draw__renderObject	;Type 8 is not defined
		B	%10draw__renderObject	;Text area is too difficult
		B	%10draw__renderObject	;Text column is too difficult
		B	%10draw__renderObject	;Options are not renderable
		B	draw__renderTransformedText ;Render rotated text
		B	draw__renderTransformedSprite ;Render rotated sprite

10		B	draw__next		;Ignore unknown objects

		LTORG

; --- draw__next ---
;
; On entry:	R7 == pointer to a draw object
;
; On exit:	R7 == pointer to next draw object
;		R0 corrupted
;
; Use:		Moves the current pointer on to the next object

draw__next	ROUT

		LDR	R0,[R7,#4]		;Load the object size
		ADD	R7,R7,R0		;Advance the object pointer
		MOVS	PC,R14			;Return to caller

		LTORG

; --- draw__clip ---
;
; On entry:	R7 == pointer to a draw object
;		R9 == pointer to current clipping rectangle
;
; On exit:	R0-R6 corrupted
;		CS if the object appears within the clipping rectangle,
;		CC if it doesn't
;
; Use:		Determines if a draw object needs rendering in the current
;		redraw job.

draw__clip	STMFD	R13!,{R7}		;Save a register
		ADD	R7,R7,#8		;Point to the bounding box
		LDMIA	R7,{R4-R7}		;Load the box from it
		LDMIA	R9,{R0-R3}		;And load the clipping box
		CMP	R0,R6			;Make sure the rectangles...
		CMPLE	R1,R7			;... overlap
		CMPLE	R4,R2
		CMPLE	R5,R3
		LDMFD	R13!,{R7}		;Restore the R7 I saved
		ORRLES	PC,R14,#C_flag		;If it is within, set C
		BICGTS	PC,R14,#C_flag		;Otherwise clear C on exit

		LTORG

; --- draw__setTextSize ---
;
; On entry:	R0 == x size in pixels
;		R1 == y size in pixels
;
; On exit:	--
;
; Use:		Sets the VDU 5 text size.

draw__setTextSize ROUT

		STMFD	R13!,{R0-R2,R14}	;Save a load of registers
		MOV	R1,R1,LSL #16		;Shift up the y sizes
		ORR	R1,R1,R0		;Add in the x sizes
		MOV	R0,#23			;Build initial VDU sequence
		ORR	R0,R0,#17<<8		;Add in more chars
		ORR	R0,R0,#7<<16
		ORR	R0,R0,#2<<24
		MOV	R2,#0			;Wrap up the sequence nicely
		STMFD	R13!,{R0-R2}		;Save it on the stack
		MOV	R0,R13			;Point to the sequence
		MOV	R1,#10			;Get the sequence size in R1
		SWI	OS_WriteN		;Write it to the VDU stream
		MOV	R14,#4			;Now set the spacing up
		STRB	R14,[R13,#3]		;Save it in the stream
		MOV	R0,R13			;Point to the sequence
		MOV	R1,#10			;Get the sequence size in R1
		SWI	OS_WriteN		;Write it to the VDU stream
		ADD	R13,R13,#12		;Restore the stack pointer
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

; --- draw__resetTextSize ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Makes the text size nice again after doing all sorts of
;		horrid things to it for the sake of plotting text in the
;		system font.

draw__resetTextSize ROUT

		STMFD	R13!,{R0,R1,R14}	;Save some registers
		BL	screen_getInfo		;Read the screen information
		LDMIA	R0,{R0,R1}		;Load the eigen factors
		MOV	R14,#16			;Normal width 16 OS units
		MOV	R0,R14,LSR R0		;Scale it into pixels
		MOV	R14,#32			;Normal height 32 OS units
		MOV	R1,R14,LSR R1		;Scale it into pixels
		BL	draw__setTextSize	;Set the pixel size nicely
		LDMFD	R13!,{R0,R1,PC}^	;And return to caller

		LTORG

;----- Object handlers ------------------------------------------------------
;
; All of these have the same entry and exit conditions as draw__renderObject.

; --- draw__readFontTable ---

draw__readFontTable ROUT

		LDR	R1,[R7,#4]		;Find the object size
		ADD	R1,R7,R1		;Convert to object end
		ADD	R0,R7,#8		;Find start of font data

		; --- Read an entry from the table ---

00		CMP	R0,R1			;Have we finished yet?
		BGE	draw__next		;Yes -- return to caller
		LDRB	R2,[R0],#1		;Get the internal font handle
		CMP	R2,#0			;Is this a null one?
		BEQ	draw__next		;Yes -- that's it then

		STR	R0,[R12,R2,LSL #2]	;Save the name pointer away
10		LDRB	R2,[R0],#1		;Get a font name character
		CMP	R2,#0			;Is this the end of the name?
		BNE	%10draw__readFontTable	;No -- go round again then

		B	%00draw__readFontTable	;Read the next font name

		LTORG

; --- draw__renderText ---

draw__renderText ROUT

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		LDMFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		; --- Make sure the text isn't invisible ---

		ADD	R6,R7,#24		;Point to the object data
		LDR	R0,[R6,#0]		;Load the foreground colour
		CMP	R0,#-1			;Is it transparent?
		MOVEQS	PC,R14			;Yes -- do nothing then

		; --- Find the font name ---

		LDR	R5,[R6,#8]		;Load internal font handle
		CMP	R5,#0			;Is the handle 0?
		BEQ	draw__renderSystemText	;Yes -- use the system font
		LDR	R5,[R12,R5,LSL #2]	;Load the font name pointer
		CMP	R5,#0			;Is it defined?
		BEQ	draw__renderSystemText	;No -- use the system font

		; --- Work out the text size I need ---

		STMFD	R13!,{R14}		;Save the link again
		ADD	R2,R6,#12		;Point to the text sizes
		LDMIA	R2,{R2,R3}		;Load x and y sizes
		LDR	R4,[R10,#0]		;Load the scale factor
		MOV	R4,R4,LSR #8		;Scale it down a little
		MUL	R2,R4,R2		;Scale up the x size
		MUL	R3,R4,R3		;And scale up the y size
		MOV	R4,#5			;So div10 rounds to nearest
		ADD	R2,R4,R2,LSR #10	;Scale values down further
		ADD	R3,R4,R3,LSR #10	;Both the x and the y
		MOV	R0,R2			;Get the x size
		BL	div10			;Convert to points
		MOV	R2,R0			;Move back into position
		MOV	R0,R3			;Get the y size
		BL	div10			;Convert to points
		MOV	R3,R0			;Move back into position
		LDMFD	R13!,{R14}		;Restore the link again

		; --- Get a font handle ---

		MOV	R1,R5			;Get the font name pointer
		MOV	R4,#0			;Default scaling, please
		MOV	R5,#0			;On x and y axes
		SWI	XFont_FindFont		;Try to get a font handle
		BVS	draw__renderSystemText	;Couldn't -- use system font

		; --- Set the right colours ---

		LDR	R1,[R6,#4]		;Load the background colour
		LDR	R2,[R6,#0]		;Load the foreground colour
		MOV	R3,#14			;Antialias lots and lots
		SWI	ColourTrans_SetFontColours

		; --- Work out where to paint the text ---

		ADD	R3,R6,#20		;Point to the coordinates
		LDMIA	R3,{R3,R4}		;Load the coordinates out
		LDR	R5,[R10,#0]		;Load the scale factor out
		MOV	R5,R5,LSR #8		;Scale it down a little
		MUL	R3,R5,R3		;Multiply up the x position
		MUL	R4,R5,R4		;Multiply up the y position
		MOV	R3,R3,ASR #16		;Scale down the x position
		MOV	R4,R4,ASR #16		;Scale down the y position
		ADD	R1,R10,#16		;Point to the plot offset
		LDMIA	R1,{R1,R2}		;Load the offsets out
		ADD	R3,R3,R1,ASR #8		;Add it on (convert to OS)
		ADD	R4,R4,R2,ASR #8		;Convert the y coordinate too

		; --- Paint the actual text then ---

		ADD	R1,R6,#28		;Point to the text string
		MOV	R2,#&10			;Coordinates are in OS units
		SWI	Font_Paint		;Paint the text on the screen

		; --- Tidy everything up then ---

		SWI	Font_LoseFont		;Lose the font handle now
		B	draw__next		;Find next draw object

		LTORG

; --- draw__renderSystemText ---
;
; Notes:	This routine is entered with R6 set up as pointer to the
;		specific object data, and havng made sure that the text
;		actually does have to be rendered.

draw__renderSystemText ROUT

		; --- Set up the plotting colour ---

		STMFD	R13!,{R14}		;Save the link register
		LDR	R0,[R6,#0]		;Load the foreground colour
		MOV	R3,#0			;Don't bother dithering it
		MOV	R4,#0			;And set normal GCOL action
		SWI	ColourTrans_SetGCOL	;Set up the colour

		; --- Set up the text size ---

		BL	screen_getInfo		;Get things about the screen
		LDMIA	R0,{R2,R3}		;Load the eigen factors
		ADD	R14,R6,#12		;Point to the size arguments
		LDMIA	R14,{R0,R1}		;Load the text sizes out
		LDR	R4,[R10,#0]		;Load the scale factor
		MOV	R4,R4,LSR #8		;Shift it down a little
		MUL	R0,R4,R0		;Multiply x size up
		MUL	R1,R4,R1		;Multiply y size up too
		MOV	R0,R0,LSR #16		;Scale x size down more
		MOV	R0,R0,LSR R2		;And divide by pixel size
		MOV	R1,R1,LSR #16		;Scale y size down more
		MOV	R1,R1,LSR R3		;And divide by pixel size
		BL	draw__setTextSize	;Set the VDU 5 text size
		MOV	R3,R1,LSL R3		;Multply y size up a bit

		; --- Move to the right place ---

		ADD	R14,R6,#20		;Point to the position data
		LDMIA	R14,{R1,R2}		;Load the text positions
		MUL	R1,R4,R1		;Scale up the x position
		MUL	R2,R4,R2		;Scale up the y position
		MOV	R1,R1,ASR #16		;Scale down the x pos
		MOV	R2,R2,ASR #16		;Scale down the y pos
		SUB	R3,R3,R3,LSR #3		;Find 7/8 of character height
		ADD	R2,R2,R3		;Find top of text line
		ADD	R14,R10,#16		;Find render offsets nicely
		LDMIA	R14,{R3,R4}		;Load the offsets out
		ADD	R1,R1,R3,ASR #8		;Add them and convert to OS
		ADD	R2,R2,R4,ASR #8		;Both the x and the y please
		MOV	R0,#4			;Move cursor absolute
		SWI	OS_Plot			;Move graphics cursor nicely

		; --- Plot the text and go home ---

		ADD	R0,R6,#28		;Point to the text string
		SWI	OS_Write0		;Plot it on the screen
		LDMFD	R13!,{R14}		;Unstack the link register
		B	draw__next		;And move to the next object

		LTORG

; --- draw__renderPath ---

draw__renderPath ROUT

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		LDMCCFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		LDR	R6,[R7,#36]		;Load the path style word
		TST	R6,#&80			;Is there a dot-dash pattern?
		ADDEQ	R5,R7,#40		;No -- find path data then
		LDRNE	R5,[R7,#44]		;Yes -- load dot-dash length
		ADDNE	R5,R7,R5,LSL #2		;Add this to object start
		ADDNE	R5,R5,#48		;And add fixed part of dash

		; --- Handle the filled in bit ---

		LDR	R0,[R7,#24]		;Load the fill colour
		CMP	R0,#-1			;Is it transparent?
		BEQ	%50draw__renderPath	;Yes -- just draw outline

		; --- Render a filled path ---

		MOV	R3,#&100		;Try and dither the fill
		MOV	R4,#0			;Set normal GCOL action
		SWI	ColourTrans_SetGCOL	;Set the colour up

		MOV	R0,#&c80000		;The basic flatness is 200
		LDR	R1,[R10,#0]		;Load the scale factor
		BL	div_round		;Divide to get the flatness
		MOV	R3,R0			;Get flatness in R3 nicely

		AND	R1,R6,#&40		;Get the path winding rule
		MOV	R1,R1,LSR #5		;Shift it down into place
		ORR	R1,R1,#&30		;And add in other fill bits
		MOV	R0,R5			;Point to path specification
		MOV	R2,R10			;Point to transform matrix
		SWI	Draw_Fill		;And render the filled path

		; --- Now handle an outline ---

50		LDR	R0,[R7,#28]		;Load the outline colour
		CMP	R0,#-1			;Is it transparent?
		BEQ	%90draw__renderPath	;Yes -- wrap everything up

		; --- Render a path outline ---

		MOV	R3,#&100		;Try and dither the outline
		MOV	R4,#0			;Set normal GCOL action
		SWI	ColourTrans_SetGCOL	;Set the colour up

		; --- Build the cap and join block ---
		;
		; Note that in fact the end cap and start cap specs are
		; reversed.  This is a result of Acorn stupidity, bad
		; documentation, or both.  We sit back and laugh as
		; WimpExtension gets it wrong.

		AND	R0,R6,#&03		;Get the join style style
		AND	R4,R6,#&30		;Get the start cap style
		ORR	R0,R0,R4,LSL #12	;Move that into byte 2
		AND	R4,R6,#&0C		;Get the end cap style
		ORR	R0,R0,R4,LSL #6		;Move that into byte 1

		MOV	R1,#&A0000		;Mitre limit is 10.0

		AND	R2,R6,#&00FF0000	;Get triangle cap width
		MOV	R2,R2,LSR #12		;Move it into position
		AND	R4,R6,#&FF000000	;Get triangle cap height
		ORR	R2,R2,R4,LSR #4		;Move that into position

		MOV	R3,R2			;End triangle == start one

		STMFD	R13!,{R0-R3}		;Save cap and join spec

		; --- Finally, plot the path ---

		MOV	R0,#&c80000		;The basic flatness is 200
		LDR	R1,[R10,#0]		;Load the scale factor
		BL	div_round		;Divide to get the flatness
		MOV	R3,R0			;Get flatness in R3 nicely
		MOV	R0,R5			;Point to the path spec
		MOV	R1,#&38			;A set fill style, please
		MOV	R2,R10			;Point to transform matrix
		LDR	R4,[R7,#32]		;Load the line width
		MOV	R5,R13			;Point to join and cap block
		TST	R6,#&80			;Is there a dash pattern?
		MOVEQ	R6,#0			;No -- don't plot one then
		ADDNE	R6,R7,#40		;Yes -- find the data
		SWI	Draw_Stroke		;Plot the path outline
		ADD	R13,R13,#16		;Recover used stack space

		; --- Wrap it all up nicely ---

90		LDMFD	R13!,{R14}		;Restore the link again
		B	draw__next		;Find the next draw object

		LTORG

; --- draw__renderSprite ---

draw__renderSprite ROUT

		; --- Make sure I have to render it ---

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		LDMCCFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		; --- Get a colour translation table for it ---

		ADD	R0,R7,#24		;Point to the sprite def
		MOV	R1,R11			;Put table in scratchpad
		BL	sprite_getTable		;Find a translation table

		; --- Work out the correct scaling ---

		MOV	R0,#40			;Read sprite info
		ADD	R0,R0,#512		;Sprite is pointed at
		MOV	R1,#&1000		;Don't care about sprite area
		ADD	R2,R7,#24		;Point to sprite block
		SWI	OS_SpriteOp		;Read the sprite info
		BL	screen_getInfo		;Read some screen info
		LDMIA	R0,{R0,R1}		;Load the eigen factors
		MOV	R5,R4,LSL R1		;Scale the y value into R5
		MOV	R4,R3,LSL R0		;Scale the x value into R4

		ADD	R0,R7,#8		;Point to sprite bounding box
		LDMIA	R0,{R0-R3}		;Load the values out
		SUB	R2,R2,R0		;Get sprite width in R2
		SUB	R3,R3,R1		;Get sprite height in R3
		MOV	R2,R2,LSR #8		;Scale the dimensions down
		MOV	R3,R3,LSR #8		;In both directions
		LDR	R14,[R10,#0]		;Load the scale factor
		MUL	R2,R14,R2		;Scale the x size
		MUL	R3,R14,R3		;And the y size
		MOV	R2,R2,LSR #16		;And scale the value down
		MOV	R3,R3,LSR #16		;Both directions again
		STMFD	R13!,{R2-R5}		;Save the resulting zoom blk

		MOV	R14,R14,LSR #8		;Shift scale factor down
		MUL	R3,R14,R0		;Scale the x position
		MUL	R4,R14,R1		;And the y position
		MOV	R3,R3,ASR #16		;Scale down the resulting pos
		MOV	R4,R4,ASR #16		;In both directions
		ADD	R0,R10,#16		;Find the transform offsets
		LDMIA	R0,{R0,R1}		;Load them from the block
		ADD	R3,R3,R0,ASR #8		;Add the x offset on
		ADD	R4,R4,R1,ASR #8		;Add the y offset on too

		; --- Now plot the sprite in the right place ---

		STMFD	R13!,{R7}		;Save R7 -- we need to use it
		MOV	R0,#52			;Plot sprite scaled, please
		ADD	R0,R0,#512		;Tell it I have a sprite ptr
		MOV	R1,#&1000		;A dummy sprite area
		ADD	R2,R7,#24		;Point to the sprite def
		MOV	R5,#8			;Plot with mask, please
		ADD	R6,R13,#4		;Point to my zoom block
		MOV	R7,R11			;Point to my translate table
		SWI	OS_SpriteOp		;Plot the sprite
		LDMFD	R13!,{R7}		;Unstack R7 again
		ADD	R13,R13,#16		;Recover the zoom block
		LDMFD	R13!,{R14}		;Unstack the link register
		B	draw__next		;And render the next object

		LTORG

; --- draw__renderGroup ---

draw__renderGroup ROUT

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		LDMFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		ADD	R7,R7,#36		;Render the objects in there
		MOVS	PC,R14			;I've mangled the object ptr

		LTORG

; --- draw__renderTagged ---

draw__renderTagged ROUT

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		LDMCCFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		STMFD	R13!,{R7,R8}		;Save the object pointer
		ADD	R7,R7,#28		;Point to the enclosed object
		LDR	R8,[R7,#4]		;Get the object size
		ADD	R8,R7,R8		;Point past the object
		BL	draw__doRender		;Render the object
		LDMFD	R13!,{R7,R8,R14}	;Restore registers
		B	draw__next		;And move to the next object

		LTORG

; --- draw__renderTransformedText ---

draw__renderTransformedText ROUT

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		BLCS	rov_version		;Get the current OS version
		CMPCS	R0,#300			;Is it RISC OS 3 yet?
		LDMFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		; --- Make sure the text isn't invisible ---

		ADD	R6,R7,#24		;Point to the object data
		LDR	R0,[R6,#0]		;Load the foreground colour
		CMP	R0,#-1			;Is it transparent?
		MOVEQS	PC,R14			;Yes -- do nothing then

		; --- Find the font name ---

		LDR	R5,[R6,#36]		;Load internal font handle
		CMP	R5,#0			;Is the handle 0?
		BEQ	%90draw__renderTransformedText
		LDR	R5,[R12,R5,LSL #2]	;Load the font name pointer
		CMP	R5,#0			;Is it defined?
		BEQ	%90draw__renderTransformedText

		; --- Work out the text size I need ---

		STMFD	R13!,{R14}		;Save the link again
		ADD	R2,R6,#40		;Point to the text sizes
		LDMIA	R2,{R2,R3}		;Load x and y sizes
		LDR	R4,[R10,#0]		;Load the scale factor
		MOV	R4,R4,LSR #8		;Scale it down a little
		MUL	R2,R4,R2		;Scale up the x size
		MUL	R3,R4,R3		;And scale up the y size
		MOV	R4,#5			;So div10 rounds to nearest
		ADD	R2,R4,R2,LSR #10	;Scale values down further
		ADD	R3,R4,R3,LSR #10	;Both the x and the y
		MOV	R0,R2			;Get the x size
		BL	div10			;Convert to points
		MOV	R2,R0			;Move back into position
		MOV	R0,R3			;Get the y size
		BL	div10			;Convert to points
		MOV	R3,R0			;Move back into position
		LDMFD	R13!,{R14}		;Restore the link again

		; --- Get a font handle ---

		MOV	R1,R5			;Get the font name pointer
		MOV	R4,#0			;Default scaling, please
		MOV	R5,#0			;On x and y axes
		SWI	XFont_FindFont		;Try to get a font handle
		BVS	%90draw__renderTransformedText

		; --- Set the right colours ---

		LDR	R1,[R6,#32]		;Load the background colour
		LDR	R2,[R6,#28]		;Load the foreground colour
		MOV	R3,#14			;Antialias lots and lots
		SWI	ColourTrans_SetFontColours

		; --- Work out where to paint the text ---

		ADD	R3,R6,#48		;Point to the coordinates
		LDMIA	R3,{R3,R4}		;Load the coordinates out
		LDR	R5,[R10,#0]		;Load the scale factor out
		MOV	R5,R5,LSR #8		;Scale it down a little
		MUL	R3,R5,R3		;Multiply up the x position
		MUL	R4,R5,R4		;Multiply up the y position
		MOV	R3,R3,ASR #16		;Scale down the x position
		MOV	R4,R4,ASR #16		;Scale down the y position
		ADD	R1,R10,#16		;Point to the plot offset
		LDMIA	R1,{R1,R2}		;Load the offsets out
		ADD	R3,R3,R1,ASR #8		;Add it on (convert to OS)
		ADD	R4,R4,R2,ASR #8		;Convert the y coordinate too

		; --- Scale position to millipoints ---
		;
		; Multiply by 500 (very quickly)

		ADD	R3,R3,R3,LSL #2		;Multiply R3 by 5 (*5)
		ADD	R3,R3,R3,LSL #2		;Multiply R3 by 5 (*25)
		MOV	R3,R3,LSL #4		;Multiply R3 by 16 (*400)

		ADD	R4,R4,R4,LSL #2		;Multiply R3 by 5 (*5)
		ADD	R4,R4,R4,LSL #2		;Multiply R3 by 5 (*25)
		MOV	R4,R4,LSL #4		;Multiply R3 by 16 (*400)

		; --- Paint the actual text then ---

		ADD	R1,R6,#56		;Point to the text string
		LDR	R2,[R6,#24]		;Load the special magic flags
		MOV	R2,R2,LSL #9		;Shift flags into position
		ORR	R2,R2,#&40		;Specify transform matrix
		STMFD	R13!,{R0}		;Save the font handle
		SWI	XFont_Paint		;Paint the text on the screen
		LDMFD	R13!,{R0}		;Restore the font handle

		; --- Tidy everything up then ---

		SWI	Font_LoseFont		;Lose the font handle now
90		B	draw__next		;Find next draw object

		LTORG

; --- draw__renderTransformedSprite ----

draw__renderTransformedSprite ROUT

		; --- Make sure I have to render it ---

		STMFD	R13!,{R14}		;Save the link temporarily
		BL	draw__clip		;Do we have to render it?
		BLCS	rov_version		;Get the current OS version
		CMPCS	R0,#300			;Is it RISC OS 3 yet?
		LDMCCFD	R13!,{R14}		;Restore the link again
		BCC	draw__next		;No -- then return

		; --- Get a colour translation table for it ---

		ADD	R0,R7,#48		;Point to the sprite def
		MOV	R1,R11			;Put table in scratchpad
		BL	sprite_getTable		;Find a translation table

		; --- Build the transformation matrix ---

		ADD	R14,R7,#24		;Find the transform matrix
		LDMIA	R14,{R0-R5}		;Load all the bits I need
		LDR	R6,[R10,#0]		;Load the scale factor
		MOV	R6,R6,LSR #8		;Shift scale factor down
		MOV	R0,R0,ASR #8		;Also shift down sprite scale
		MOV	R1,R1,ASR #8		;Also shift down sprite scale
		MOV	R2,R2,ASR #8		;Also shift down sprite scale
		MOV	R3,R3,ASR #8		;Also shift down sprite scale
		MUL	R0,R6,R0		;Apply scale to sprite matrix
		MUL	R1,R6,R1		;Apply scale to sprite matrix
		MUL	R2,R6,R2		;Apply scale to sprite matrix
		MUL	R3,R6,R3		;Apply scale to sprite matrix
		SUB	R13,R13,#24		;Make space for matrix
		STMIA	R13,{R0-R3}		;Save transform on stack
		ADD	R14,R10,#16		;Point to my offsets
		LDMIA	R14,{R0,R1}		;Load the offsets out
		MUL	R4,R6,R4		;Scale the sprite x offset
		MUL	R5,R6,R5		;Scale the sprite y offset
		ADD	R4,R0,R4,ASR #8		;Add on to original offset
		ADD	R5,R1,R5,ASR #8		;Add on to original offset
		ADD	R14,R13,#16		;Point to bit of matrix
		STMIA	R14,{R4,R5}		;Save these in the matrix

		; --- Now plot the sprite in the right place ---

		STMFD	R13!,{R7}		;Save R7 -- we need to use it
		MOV	R0,#56			;Plot sprite scaled, please
		ADD	R0,R0,#512		;Tell it I have a sprite ptr
		MOV	R1,#&1000		;A dummy sprite area
		ADD	R2,R7,#48		;Point to the sprite def
		MOV	R3,#0			;R6 points to a matrix
		MOV	R4,#0			;No source rectangle thing
		MOV	R5,#8			;Plot with mask, please
		ADD	R6,R13,#4		;Point to my matrix
		MOV	R7,R11			;Point to my translate table
		SWI	OS_SpriteOp		;Plot the sprite
		LDMFD	R13!,{R7}		;Unstack R7 again
		ADD	R13,R13,#24		;Recover the matrix block
		LDMFD	R13!,{R14}		;Unstack the link register
		B	draw__next		;And render the next object

		LTORG

;----- That's all, folks ----------------------------------------------------

		END
