;
; border.s
;
; Plots borders given an icon block and a definition of the border shape
;
;  1995-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sculptrix.
;
; Sculptrix 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.
;
; Sculptrix 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 Sculptrix.  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

		GET	libs:stream

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

		GET	sh.colours
		GET	sh.wSpace

		GET	sh.messages

;----- The idea -------------------------------------------------------------
;
; We store the border shapes as commands in blocks, and then read them out
; when plotting needs to be done.
;
; The commands are very simple, and are one byte wide each.  Some commands
; have arguments which are stored in the following byte or word.  Whole
; word arguments are preceded by padding to a word boundary.  It ends up
; looking a bit like a simple `machine code'.

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

		AREA	|Module$$Code|,CODE,READONLY

; --- border_plot ---
;
; On entry:	R0 == pointer to border defintion
;		R1 == pointer to icon block
;		R2,R3 == window origin position
;		R4 == pointer to colour table
;		R5 == group box title width (optional)
;		R6 == group box title address (optional)
;
; On exit:	May return an error
;
; Use:		Plots a border using the border definition.

		EXPORT	border_plot
border_plot	ROUT

		STMFD	R13!,{R0-R11,R14}	;Save lots of registers

		; --- Set up some environment ---

		MOV	R10,R0			;Point at the border routine

		ADR	R14,sculpt_vduVars	;Point to the VDU variables
		LDMIA	R14,{R7-R9}		;Load these for the rule rtns

		LDMIA	R1,{R4-R6,R14}		;Load the icon position

		SUB	R0,R7,#1		;Turn this into a bitmask
		BIC	R4,R4,R0		;Mask the x coordinates
		BIC	R6,R6,R0		;To avoid nasty problems
		SUB	R0,R8,#1		;Turn this into a bitmask
		BIC	R5,R5,R0		;Mask the y coordinates
		BIC	R14,R14,R0		;To avoid nasty problems

		ADD	R4,R4,R2		;Convert to screen coords
		ADD	R5,R5,R3		;Convert to screen coords
		ADD	R6,R6,R2		;Convert to screen coords
		ADD	R14,R14,R3		;Convert to screen coords

		STMFD	R13!,{R4-R6,R14}	;These are initial reg values
		MOV	R11,R13			;Remember this position

		; --- Now start executing ---

border__main	LDRB	R14,[R10],#1		;Load the next instruction
		AND	R0,R14,#3		;Fetch immediate op bits
		BIC	R14,R14,#3		;Clear them from the byte
		CMP	R14,#(%10-%00)		;Is instruction known?
		ADDCC	PC,PC,R14		;Yes -- dispatch it then
		B	%10border_plot		;If unknown, report error

00		B	border__ret		;End the routine
		B	border__iLoad		;Load a value from the icon
		B	border__load		;Load a stored value
		B	border__ldCtr		;Load a centrepoint
		B	border__op		;Do an op on the value
		B	border__store		;Store value in output blk
		B	border__stdCol		;Standard colour selection
		B	border__colour		;Other colour ops
		B	border__plot		;Plot a rule
		B	border__skipTtl		;Skip over the group title
		B	border__plotGrp		;Plot a group box
		B	border__call		;Call a subroutine

10border_plot	ADRL	R0,msg_errBadOpcode	;Point to the error message
		ADD	R13,R11,#16+4		;Restore the stack pointer
		LDMFD	R13!,{R1-R11,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return the error

		; --- border__ret ---

border__ret	CMP	R13,R11			;Are we at top level?
		LDMCCFD	R13!,{R10}		;No -- restore our IP
		BCC	border__main		;And continue

		ADD	R13,R11,#16		;Restore stack pointer
		LDMFD	R13!,{R0-R11,R14}	;Restore registers
		BICS	PC,R14,#V_flag		;And return with glad tidings

		; --- border__iLoad ---

border__iLoad	LDR	R6,[R1,R0,LSL #2]	;Load the requested value
border__round	TST	R0,#1			;Is this a y-coordinate?
		ADDEQ	R6,R6,R2		;No -- adjust by x origin
		ADDNE	R6,R6,R3		;Yes -- adjust by y origin
		SUBEQ	R14,R7,#1		;No -- get x width
		SUBNE	R14,R8,#1		;Yes -- get y width
		BIC	R6,R6,R14		;Round the value nicely
		B	border__main		;And get next instruction

		; --- border__load ---

border__load	LDR	R6,[R11,R0,LSL #2]	;Load the requested value
		B	border__main		;And get the next instruction

		; --- border__ldCtr ---

border__ldCtr	ADD	R14,R1,R0,LSL #2	;Find the correct bit
		LDMIA	R14,{R5,R6,R14}		;Load three values
		ADD	R6,R5,R14		;Add the two together
		MOV	R6,R6,ASR #1		;Divide by two
		B	border__round		;Now round the value to pixel

		; --- border__op ---

border__op	LDRB	R14,[R10],#1		;Load the next byte out
		TST	R0,#1			;Which op is it?
		ADDEQ	R6,R6,R14		;Add -- do the add then
		SUBNE	R6,R6,R14		;Sub -- do that
		B	border__main		;And skip off merrily

		; --- border__store ---

border__store	STR	R6,[R11,R0,LSL #2]	;Store it (can't trash stk)
		B	border__main		;And return to loop

		; --- border__stdCol ---

border__stdCol	TST	R0,#2			;Doing complicated things?
		BNE	%f00			;Yes -- skip forwards then
		LDR	R14,[R11,#16 + 4*4]	;Load the colour table addr
		LDRB	R0,[R14,R0]		;Load the colour out
		SWI	XWimp_SetColour		;Do the set
		B	border__main		;And loop back round

00		LDR	R14,[R11,#16 + 4*4]	;Load the colour table addr
		BIC	R14,R14,#&03		;Clear non-alignedness
		STR	R14,[R11,#16 + 4*4]	;Store the address back
		B	border__main		;And return to caller

		; --- border__colour ---

border__colour	CMP	R0,#0			;Is this set-from-icon?
		BEQ	%f00			;Yes -- do this
		CMP	R0,#1			;Do we indirect this?
		LDRB	R0,[R10],#1		;Load the argument byte
		LDREQB	R0,[R12,R0]		;Load the colour out
		SWI	XWimp_SetColour		;Set the colour
		B	border__main		;And loop back for more

00		BL	colours_read		;Read the colours out
		MOV	R4,R0,LSR #4		;Extract background colour
		AND	R0,R0,#&F		;Extract foreground colour
		LDR	R14,[R1,#16]		;Load the icon flags, please
		TST	R14,#&00400000		;Is icon /really/ shaded?
		ANDNE	R0,R0,#2		;Yes -- shade in simple way
		SWI	XWimp_SetColour		;Set the colour, please
		ORR	R0,R4,#&80		;Get the background colour
		SWI	XWimp_SetColour		;Set the colour, please
		B	border__main		;And continue

		; --- border__plot ---

border__plot	ADD	R10,R10,#4+3		;Word align instruction ptr
		BIC	R10,R10,#3		;And advance past the branch
		STMFD	R13!,{R1-R3,R6}		;Store useful values
		LDMIA	R11,{R3-R6}		;Load the coordinates
		MOV	R14,PC			;Set up return address
		SUB	PC,R10,#4		;Call the branch instr
		LDMFD	R13!,{R1-R3,R6}		;Restore the registers
		B	border__main		;And rejoin the loop

		; --- border__skipTtl ---

border__skipTtl	LDR	R14,[R11,#16 + 4*5]	;Load the title width
		ADD	R6,R6,R14		;Add this on nicely
		SUB	R14,R7,#1		;Get x bitmask
		BIC	R6,R6,R14		;To be nice
		B	border__main		;Go forth and execute

		; --- border__plotGrp ---

border__plotGrp	LDMIA	R11,{R4-R6,R14}		;Load the coordinates

		SUB	R4,R4,R2		;Make them window relative
		SUB	R5,R5,R3		;Keep doing this a bit
		SUB	R6,R6,R2
		SUB	R14,R14,R3

		SUB	R13,R13,#32		;Make space for the block
		STMIA	R13,{R4-R6,R14}		;Store all them away
		ADD	R10,R10,#4+3		;Word align instruction ptr
		BIC	R10,R10,#3		;And skip past flags word

		LDR	R4,[R10,#-4]		;Load the flags word
		LDR	R5,[R1,#16]		;Load the original flags
		BIC	R4,R4,#&0F400000	;Clear the static flags
		AND	R5,R5,#&0F400000	;And mask the real flags
		ORR	R4,R4,R5		;Combine them nicely

		LDR	R5,[R11,#16 + 4*6]	;Get the title
		MOV	R6,#-1			;No validation string
		MOV	R14,#1			;A random buffer length
		ADD	R0,R13,#16		;Find a space nicely
		STMIA	R0,{R4-R6,R14}		;Save the icon data
		MOV	R1,R13			;Point to this block
		SWI	XWimp_PlotIcon		;Do the icon plotting
		ADD	R13,R13,#32		;Restore the stack pointer
		LDR	R1,[R11,#16 + 4*1]	;Reload the icon pointer
		B	border__main		;Done that

		; --- border__call ---

border__call	ADD	R10,R10,#4+3		;Word align instruction ptr
		BIC	R10,R10,#3		;And advance past the branch
		TST	R0,#1			;Do we save the old one?
		STMNEFD	R13!,{R10}		;Yes -- save old IP on stack
		LDR	R14,[R10,#-4]		;Load the branch offset
		ADD	R10,R10,R14		;Find the new routine
		B	border__main		;Continue executing subrt

		LTORG

;----- Command codes --------------------------------------------------------
;
; We try to organise these in a way which makes it easy to decode.  The
; bottom two bits end up as an immediate operand in most cases, allowing us
; to select entries in the icon bounding box easily.

		^	-4

		#	4
bCmd_ret	EQU	{VAR}			;End border operation

		#	4
bCmd_ldix0	EQU	{VAR}+0			;Fetch X0 of the icon
bCmd_ldiy0	EQU	{VAR}+1			;Fetch Y0 of the icon
bCmd_ldix1	EQU	{VAR}+2			;Fetch X1 of the icon
bCmd_ldiy1	EQU	{VAR}+3			;Fetch Y1 of the icon

		#	4
bCmd_ldx0	EQU	{VAR}+0			;Fetch last stored X0
bCmd_ldy0	EQU	{VAR}+1			;Fetch last stored Y0
bCmd_ldx1	EQU	{VAR}+2			;Fetch last stored X1
bCmd_ldy1	EQU	{VAR}+3			;Fetch last stored Y1

		#	4
bCmd_ldhc	EQU	{VAR}+0			;Fetch horizontal centre
bCmd_ldvc	EQU	{VAR}+1			;Fetch vertical centre

		#	4
bCmd_add	EQU	{VAR}+0			;Add next byte
bCmd_sub	EQU	{VAR}+1			;Subtract next byte

		#	4
bCmd_stx0	EQU	{VAR}+0			;Store as the X0 parameter
bCmd_sty0	EQU	{VAR}+1			;Store as the Y0 parameter
bCmd_stx1	EQU	{VAR}+2			;Store as the X1 parameter
bCmd_sty1	EQU	{VAR}+3			;Store as the Y1 parameter

		#	4
bCmd_dark	EQU	{VAR}+0			;Use the current `dark' col
bCmd_light	EQU	{VAR}+1			;Use the current `light' col
bCmd_raw	EQU	{VAR}+2			;Switch to uninverted colours

		#	4
bCmd_icon	EQU	{VAR}+0			;Set colours from icon
bCmd_indCol	EQU	{VAR}+1			;Indirected colour
bCmd_litCol	EQU	{VAR}+2			;Literal colour

		#	4
bCmd_plot	EQU	{VAR}+0			;Plot a rule (arg == branch)

		#	4
bCmd_skpt	EQU	{VAR}+0			;Skip past the `title'

		#	4
bCmd_group	EQU	{VAR}+0			;Plot a group box

		#	4
bCmd_jmp	EQU	{VAR}+0			;Jump to a routine
bCmd_call	EQU	{VAR}+1			;Call subroutine

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

		END
