;
; screen.s
;
; Screen mode information caching (TMA)
;
;  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:sapphire
		GET	sapphire:event

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- screen_getInfo ---
;
; On entry:	--
;
; On exit:	R0 == pointer to screen information block
;
; Use:		This call returns a pointer to a block of information
;		about the current screen modes.  The format of this block
;		is defined above.

		EXPORT	screen_getInfo
screen_getInfo	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R0,screen__wSpace	;Get my workspace offset
		LDR	R14,sapph_workspace	;Load workspace base address
		ADD	R0,R14,R0		;Find workspace address
		ADD	R0,R0,#4		;Point to the data block
		LDMFD	R13!,{PC}^		;Return to caller

		LTORG

; --- screen_cache ---
;
; On entry:	R12 points to workspace
;
; On exit:	--
;
; Use:		Caches screen information for the current mode.

		EXPORT	screen_cache
screen_cache	ROUT

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

		; --- Now read relevent mode variables ---

		MOV	R3,#1			;A useful value
		MOV	R0,#-1			;Get info on current mode

		MOV	R1,#4			;XEigFactor
		SWI	OS_ReadModeVariable	;Read its value
		MOV	R4,R2		        ;Look after xEig
		MOV	R9,R3,LSL R4		;Get dx correctly

		MOV	R1,#5			;YEigFactor
		SWI	OS_ReadModeVariable	;Read its value
		MOV	R5,R2	    		;Look after yEig
		MOV	R10,R3,LSL R5		;Get dy correctly

		MOV	R1,#9			;Log2BPP
		SWI	OS_ReadModeVariable	;Read its value
		MOV	R6,R3,LSL R2	        ;Calculate bpp

		MOV	R1,#11			;XWindLimit
		SWI	OS_ReadModeVariable	;Read its value
		ADD	R2,R2,#1		;Calculate screen width
		MOV	R7,R2,LSL R4		;width=(XwindLimit+1)<<xEig

		MOV	R1,#12			;XWindLimit
		SWI	OS_ReadModeVariable	;Read its value
		ADD	R2,R2,#1		;Calculate screen width
		MOV	R8,R2,LSL R5		;height=(YwindLimit+1)<<yEig

		; --- Now store the cached information ---

		STMIB	R12,{R4-R10}		;Store in my workspace

		; --- And return to caller ---

		LDMFD	R13!,{R0-R10,PC}^	;Return

		LTORG

; --- screen__postFilter ---
;
; On entry:	R0 == wimp event type
;		R1 == pointer to returned block
;		R12 == pointer to my workspace
;
; On exit:	--
;
; Use:		Called as a post filter to cache screen information on
;		a mode change.

screen__postFilter
		ROUT

		; --- Do we want this event ---

		CMP	R0,#2			;Open window request?
		MOVEQS	PC,R14			;Yes -- return PDQ

		STMFD	R13!,{R0,R2,R14}	;Save registers
		LDR	R2,screen__flags	;Get the flags word
		CMP	R0,#17			;Is event a message?
		CMPNE	R0,#18
		BICNE	R2,R2,#sFlag__newMode	;No -- clear 'changed mode'
		STRNE	R2,screen__flags	;...store back flags
	 	LDMNEFD	R13!,{R0,R2,PC}^	;...and return

		; --- Is it the right message ---

		LDR	R14,[R1,#16]		;Get the message type
		LDR	R0,=&400C1		;Is it a mode change?
		CMP	R14,R0			;Compare the values
		BICNE	R2,R2,#sFlag__newMode	;No -- clear 'changed mode'
		STRNE	R2,screen__flags	;...store back flags
		LDMNEFD	R13!,{R0,R2,PC}^	;...and return

		; --- Cache the mode information ---

		ORR	R2,R2,#sFlag__newMode	;Set 'changed mode' bit
		STR	R2,screen__flags	;Store back flags
		BL	screen_cache		;Cache screen info

		; --- And return ---

		LDMFD	R13!,{R0,R2,PC}^	;Return to caller

		LTORG

; --- screen_justChangedMode ---
;
; On entry:	--
;
; On exit:	CS if last event was a mode change, CC otherwise
;
; Use:		Informs the caller if the last event was a mode change.
;		The system ignores open window requests when making it's
;		decision.

		EXPORT	screen_justChangedMode
screen_justChangedMode ROUT

		STMFD	R13!,{R12,R14}		;Stack some registers
		WSPACE	screen__wSpace		;Locate my workspace

		LDR	R14,screen__flags	;Get the flags word
		TST	R14,#sFlag__newMode	;Test relevant bit
		LDMFD	R13!,{R12,R14}		;Restore my registers
		BICEQS	PC,R14,#C_flag		;It wasn't -- clear carry
		ORRNES	PC,R14,#C_flag		;It was -- set carry

		LTORG

; --- screen_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the screen unit.

		EXPORT	screen_init
screen_init	ROUT

		STMFD	R13!,{R0,R1,R12,R14}	;Stack some registers
		WSPACE	screen__wSpace		;Get my workspace

		; --- Are we already initialised? ---

		LDR	R0,screen__flags	;Get my flags
		TST	R0,#sFlag__inited	;Are we initialised?
		LDMNEFD	R13!,{R0,R1,R12,PC}^	;Yes -- return

		ORR	R0,R0,#sFlag__inited	;Set flags
		STR	R0,screen__flags	;And store them back

		; --- Now cache the current mode info ---

		BL	screen_cache

		; --- Ensure that the event system is initialised ---

		BL	event_init

		; --- Finally, set up a post filter to catch mode changes ---

		ADR	R0,screen__postFilter	;Routine to call
		MOV	R1,R12			;Put my workspace in R12
		BL	event_postFilter	;Add the post filter

		; --- That's it now ---

		LDMFD	R13!,{R0,R1,R12,PC}^	;Return

		LTORG

screen__wSpace	DCD	0			;My workspace pointer

;----- Workspace ------------------------------------------------------------

		^	0,R12
screen__wStart	#	0

screen__flags	#	4			;Flags

screen__xEig	#	4			;X Eig Factor
screen__yEig	#	4			;Y Eig Factor
screen__bpp	#	4			;Bits per pixel
screen__width	#	4			;Current screen width
screen__height	#	4			;Current screen height
screen__dx	#	4			;x pixel size
screen__dy	#	4			;y pixel size

screen__wSize	EQU	{VAR}-screen__wStart

sFlag__inited	EQU	(1<<0)			;I've been initialised
sFlag__newMode	EQU	(1<<1)			;Mode change just happened

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	screen__wSize		;Workspace size
		DCD	screen__wSpace		;Workspace pointer
		DCD	0			;Scratchpad size
		DCD	screen_init		;Initialisation code

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

		END
