;
; sprite.s
;
; Nice operations on sprites
;
;  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:resspr
		GET	sapphire:screen

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- sprite_op ---
;
; On entry:	R0,R2-R7 ==  SpriteOp parameters (R1 set up here)
;
; On exit:	Registers and flags altered as for the SpriteOp
;
; Use:		Performs an OS_SpriteOp with the given arguments, using
;		the appication's Sprites resource as the sprite area.

		EXPORT	sprite_op
sprite_op	ROUT

		STMFD	R13!,{R0,R14}		;Stack some registers

		; --- Get the current resource sprite area ---

		BL	resspr_area		;Get area in R0
		MOV	R1,R0			;Put it in R1
		LDMFD	R13!,{R0}		;Get the SpriteOp back

		; --- Is it the WIMP sprite area (Yrggg...) ---

		CMP	R1,#1			;Is it WIMP area?
		BEQ	%00sprite_op		;Yes -- deal with it

		; --- We must be using the user sprite area ---

		ORR	R0,R0,#&100		;Use user area
		SWI	XOS_SpriteOp		;Do the SpriteOp
		LDMFD	R13!,{PC}		;And return to the user

		; --- Use the WIMP sprite area ---

00sprite_op	SWI	XWimp_SpriteOp		;Do SpriteOp on WIMP area
		LDMFD	R13!,{PC}		;And return to the user

		LTORG

; --- sprite_getTable ---
;
; On entry:	R0 == pointer to a sprite
;		R1 == pointer to buffer for translate table
;
; On exit:	--
;
; Use:		Creates a colour translate table for the given sprite in
;		the specified buffer.
;
;		If you have a sprite name but no pointer, use OS_SpriteOp
;		24 to find the pointer -- this will make further sprite ops
;		on the sprite much quicker.

		EXPORT	sprite_getTable
sprite_getTable	ROUT

		STMFD	R13!,{R0-R9,R14}	;Save some registers
		MOV	R7,R0			;Keep the sprite pointer
		MOV	R8,R1			;Keep the buffer pointer

		; --- Find out how many colours the sprite has ---

		MOV	R2,R7			;Get the sprite pointer
		MOV	R1,#&1000		;No particular sprite area
		MOV	R0,#40			;Get sprite information
		ADD	R0,R0,#512		;Tell it I have a sprite ptr
		SWI	OS_SpriteOp		;Read the sprite information
		MOV	R0,R6			;Get the sprite's mode
		MOV	R1,#3			;Read number of colours
		SWI	OS_ReadModeVariable	;Read the mode value nicely
		MOV	R9,R2			;Keep number of colours

		; --- Handle the Wimp palette ---
                ;
                ; If the sprite has 16 colours and no palette, we assume it
                ; should have the Wimp palette, and so use that.

		CMP	R2,#15			;Does it have 16 colours?
		LDREQ	R14,[R7,#32]		;Get the sprite offset
		CMPEQ	R14,#44			;Is there no palette?
		BNE	%10sprite_getTable	;No to either -- skip it out

		; --- Read the WIMP palette, and use that ---

		SUB	R13,R13,#80		;Drop the stack pointer
		MOV	R1,R13			;Point to the block
		SWI	Wimp_ReadPalette	;Read the Wimp palette
		MOV	R0,R6			;Source mode set up
		MOV	R2,#-1			;Use current mode
		MOV	R3,#-1			;Use current palette too
		MOV	R4,R8			;Create in caller's buffer
		SWI	ColourTrans_SelectTable	;Set up the table nicely
		ADD	R13,R13,#80		;Restore the stack pointer
		B	%90sprite_getTable	;And skip to the end

		; --- Try and use the RISC OS 3 way ---

10		MOV	R0,#&1000		;No sprite area in particular
		MOV	R1,R7			;Point to my sprite
		MOV	R2,#-1			;Output in current mode
		MOV	R3,#-1			;And into current palette
		MOV	R4,R8			;Into the caller's buffer
		MOV	R5,#1			;And output a sprite table
		SWI	XColourTrans_SelectTable ;Try and read the table
		BVC	%90sprite_getTable	;If it worked, finish

		; --- If the sprite has no palette, just assume default ---

		CMP	R9,#15			;Is the number of colours>16?
		BGT	%15sprite_getTable	;Yes -- assume def palette
		LDR	R14,[R7,#32]		;Get the sprite offset
		CMP	R14,#44			;Is there a palette?
		BNE	%20sprite_getTable	;Yes -- handle it then

15		MOV	R0,R6			;Source mode set up
		MOV	R1,#0			;Assume default palette
		MOV	R2,#-1			;Use current mode
		MOV	R3,#-1			;Use current palette too
		MOV	R4,R8			;Create in caller's buffer
		SWI	ColourTrans_SelectTable	;Set up the table nicely
		B	%90sprite_getTable	;And skip to the end

		; --- Read the palette from the sprite ---

20		ADD	R0,R7,#44		;Point to first palette entry
		SUB	R13,R13,R9,LSL #2	;And make space for palette
		MOV	R1,R13			;Point to palette buffer
		MOV	R2,R9			;Copy the colour count

25		LDR	R14,[R0],#8		;Load a palette word
		STR	R14,[R1],#4		;Save it into the buffer
		SUBS	R2,R2,#1		;Decrement the counter
		BGE	%25sprite_getTable	;If more to do, go round

		MOV	R0,R6			;Source mode set up
		MOV	R1,R13			;Point to my nice palette
		MOV	R2,#-1			;Use current mode
		MOV	R3,#-1			;Use current palette too
		MOV	R4,R8			;Create in caller's buffer
		SWI	ColourTrans_SelectTable	;Set up the table nicely
		ADD	R13,R13,R9,LSL #2	;Reclaim the stack again

		; --- Return to caller ---

90		LDMFD	R13!,{R0-R9,PC}^	;Return to caller

		LTORG

; --- sprite_plot ---
;
; On entry:	R0 == pointer to a sprite
;		R1 == x coordinate to plot at
;		R2 == y coordinate to plot at
;		R3 == pointer to scale block, or 0 for 1:1
;
; On exit:	CS if the sprite was plotted OK, else CC
;
; Use:		Plots a sprite on the screen.  The scaling refers to the
;		sprite proper: /this/ routine takes care of odd pixel
;		sizes and things, so sprites don't appear squashed or
;		stretched unless you really want them to.
;
;		We return C clear on exit if we couldn't plot the sprite;
;		typically this would be if the sprite's mode is undefined.

		EXPORT	sprite_plot
sprite_plot	ROUT

		STMFD	R13!,{R0-R9,R14}	;Save some registers

		CMP	R3,#0			;Has he given a scaling?
		ADREQ	R3,sprite__scale	;No -- use our own one
		LDMIA	R3,{R5-R8}		;Load the scaling out

		; --- Fiddle with the scale factors ---

		MOV	R3,R1			;Remember this position
		MOV	R4,R2			;And this one please
		MOV	R9,R0			;Remember the sprite addr
		BL	screen_getInfo		;Read the screen info
		ADD	R14,R0,#screen_xEig	;Find the EIG factors
		LDMIA	R14,{R0,R1}		;Load them out nicely
		MOV	R7,R7,LSL R0		;Scale down by this resn
		MOV	R8,R8,LSL R1		;So go and do that
		LDR	R0,[R9,#40]		;Load the mode gadget
		MOV	R1,#4			;Read the x EIG factor
		SWI	OS_ReadModeVariable	;Read that then
		BCS	%90sprite_plot		;If it failed, return
		MOV	R5,R5,LSL R2		;Bump up the scaling by this
		MOV	R1,#5			;Read the y EIG factor
		SWI	OS_ReadModeVariable	;Read that then
		BCS	%90sprite_plot		;If it failed, return
		MOV	R6,R6,LSL R2		;Bump up the scaling again
		STMFD	R13!,{R5-R8}		;Save them away for later

		; --- Now read the translation table and plot ---

		MOV	R0,R9			;Point to the sprite
		MOV	R1,R11			;Build table in R11-space
		BL	sprite_getTable		;Go and do that then

		MOV	R0,#52			;Put sprite scaled
		ORR	R0,R0,#512		;Use my pointed-at sprite
		MOV	R1,#&1000		;A bogus sprite area
		MOV	R2,R9			;Point to the sprite
		MOV	R5,#8			;Plot with a mask
		MOV	R6,R13			;Point to scale factors
		MOV	R7,R11			;And to the translate table
		SWI	XOS_SpriteOp		;Plot and ignore error
		ADD	R13,R13,#16		;Restore stack pointer
		BVS	%90sprite_plot		;If it failed, abort
		LDMFD	R13!,{R0-R9,R14}	;Restore registers
		ORRS	PC,R14,#C_flag		;And return to caller

90sprite_plot	LDMFD	R13!,{R0-R9,R14}	;Restore registers
		BICS	PC,R14,#C_flag		;And return to caller

sprite__scale	DCD	1,1,1,1

		LTORG

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

		END
