; Copyright 2002 Tematic Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
;
; MB 23/3/98
; Complete reimplementation of tiling code based on 3DPatch sources
;

;-------------------------------------------------------------------------------
;			  Window background drawing code
;-------------------------------------------------------------------------------

		DCB	"MIB",0

; this is a 'signed' division macro

        MACRO
$lab    DivRemS $ra,$rb,$rc,$tmp
$lab    CMP     $rb,#0
        BLT     %FT2
        DivRem  $ra,$rb,$rc,$tmp
        B       %FT4
2       RSB     $rb,$rb,#0
        DivRem  $ra,$rb,$rc,$tmp
        RSB     $rb,$rb,#0
        ; modulus should be -ve if divisor is -ve
4
        MEND

; plotspritebackground
;
; plot the textured background in a window
;
;	 on entry : 	r0 = window background colour
;	 		r6-r9 = window visible area coords
;	 		r10 = internal window block pointer
;
;	on exit:	all regs preserved
;
		ROUT
plotspritebackground
		Push	"r0-r5,lr"

		Debug	tiling,"Enterring plotspritebackground",r0,r6,r7,r8,r9,r10

		cmp	r0,#15
		bhi	%FT02

	[ TrueIcon3
		ldrb	r14,[handle,#w_flags2]		; if using true colours for window backgrounds and this window has a custom
		tst	r14,#wf2_truecolour		; background colour then don't plot a tile, just clear the background
		bne	%FT02
	]
		mov	r5,r0				; r5 = window bg colour

		ldr	r0,[handle,#w_taskhandle]
		cmp	r0,#-1				; if the current window is a menu
		bne	%FT01

		ldr	r1,ThreeDFlags
		tst	r1,#ThreeDFlags_TexturedMenus	; check if menu textures are enabled
		beq	%FT02
		tst	r1,#ThreeDFlags_UseAlternateMenuTexture ; then check which texture to use
		movne	r5,#16
		moveq	r5,#1

01
		Debug	tiling,"Calling TileWindowBackground"
		bl	TileWindowBackground
;		Debug	tiling,"Calling PlotWindowBorders"
;		bl	PlotWindowBorders

		Pull	"r0-r5,PC"

02
		swi	OS_WriteI + 16
		Pull	"r0-r5,PC"

ploticonbackgroundsprite
		Push	"r0-y1,lr"

		ldr	x0,thisCBptr
		ldr	y0,spritename
		ldr	x1,lengthflags
		Push	"x0-x1"

		adr	r14,clipx0
		ldmia	r14,{x0-y1}
		Push	"x0-y1"			; save the current clipping rectangle

		CMP	x0,cx0
		MOVLT	x0,cx0
		CMP	y0,cy0
		MOVLT	y0,cy0
		CMP	x1,cx1
		MOVGT	x1,cx1
		CMP	y1,cy1
		MOVGT	y1,cy1

		CMP	x0,x1
		CMPLT	y0,y1
		ADDGE	sp,sp,#7*4
		Pull	"r0-y1,pc",GE

		Debug	tiling,"In ploticonbackgroundsprite, about to set graphics window to : ",x0,y0,x1,y1
		BL	graphicswindow

		LDRB	r0,[handle,#w_wbcol]

		ADD	r14,handle,#w_wax0
		LDMIA	r14,{x0-y1}

		SWI	OS_WriteI + 16
		BL	plotspritebackground

		Pull	"x0-y1"
		BL	graphicswindow

		Pull	"x0-x1"
		str	x0,thisCBptr
		str	y0,spritename
		str	x1,lengthflags

		Pull	"r0-y1,pc"

tile_1		DCB	"tile_1",0
		ALIGN

TileWindowBackground
		ROUT
		Push	"r6-r11,lr"

		ldr	r1,[handle,#w_areaCBptr]
		cmp	r1,#2
		blo	%FT00

		teq	r5,#sc_verylightgrey
		bne	%FT00

		adr	r2,tile_1
		mov	r0,#SpriteReason_SelectSprite :OR: 256
		swi	XOS_SpriteOp
		bvs	%FT00

		adrl	r8,temp_tile_sprite
		bl	get_tile_sprite_info
		bvs	%FT00

		Debug	tiling,"Calling tile_sprite_fill_area"
		bl	tile_sprite_fill_area

		ldr	r2,[r8,#TileInfo_TranslationTablePtr]
		cmp	r2,#0
		movne	r0,#ModHandReason_Free
		blne	XROS_Module
		mov	r2,#0
		str	r2,[r8,#TileInfo_TranslationTablePtr]

		CLRV
		Pull	"r6-r11,PC"

00		adrl	r8,tile_sprites
		ASSERT	TileInfo = 36
		add	r0,r5,r5,LSL #3
		mov	r0,r0,LSL #2			; r0 = r5 * sizeof(TileInfo)
		add	r8,r8,r0			; r8 = ptr to correct sprite info block

		bl	get_tile_sprite			; r8 = ptr to filled in sprite info block

		blvc	tile_sprite_fill_area

   		Pull	"r6-r11,PC",VC

01		swi	XOS_WriteI + 16			; clear the screen
		CLRV
		Pull	"r6-r11,PC"

PlotWindowBorders
		ROUT
;		 on entry: r6-r9 = window visible area
;		 	     r10 = internal window block pointer
		ROUT
		Push	"r3-r5,x0-y1,lr"

		ldr	r14,ThreeDFlags
		tst	r14,#ThreeDFlags_Use3DBorders
		Pull	"r3-r5,x0-y1,pc",EQ

		ldrb	r5,[handle,#w_wbcol]

		ldr	r3,truefacecolour
		ldr	r4,trueoppcolour
		Push	"r3,r4"

		ldr	r3,iconbarhandle
		Abs	r3,r3			; convert to internal block pointer
		teq	r3,handle
		beq	%FT01

		ldr	r3,[handle,#w_taskhandle]	; check for menu
		cmp	r3,#-1
		bne	%FT04

		tst	r14,#ThreeDFlags_UseAlternateMenuTexture ; see if we need to use the window border colours or the menu colours
		beq	%FT03

		ldr	r3,truemenuborderfacecolour		; set up the menu border colours
		ldr	r4,truemenuborderoppcolour
		str	r3,truefacecolour
		str	r4,trueoppcolour
		b	%FT00

04		teq	r5,#1					; check if this window needs a border
		bne	%FT02

		ldrb	r14,[handle,#w_flags2]
		and	r14,r14,#wf2_no3Dborder :OR: wf2_force3Dborder
		teq	r14,#wf2_no3Dborder
		beq	%FT02
		teq	r14,#wf2_force3Dborder
		beq	%FT03

		ldr	r14,[handle,#w_flags]
		tst	r14,#&70000000
		tsteq	r14,#&00000020
 [ No3DChildWindows
		ldreq	r14,[handle,#w_parent]
		cmpeq	r14,#-1				; check if it's a top level window
 ]
		bne	%FT02

03		ldr	r3,truewindowborderfacecolour	; set up the window borders colours
		ldr	r4,truewindowborderoppcolour
		str	r3,truefacecolour
		str	r4,trueoppcolour

00		bl	plot_slabout

		ldr	r0,truefgcolour
		cmp	r0,#-1
		beq	%FT02
		ldr	r3,ditheringflag
		mov	r4,#0
		swi	XColourTrans_SetGCOL		; put the forground colour back the way it was before we plotted the border
02
		Pull	"r3,r4"
		str	r3,truefacecolour
		str	r5,trueoppcolour

		Pull	"r3-r5,x0-y1,pc"

01		tst	r14,#ThreeDFlags_Fully3DIconBar
		subeq	x0,x0,#16		; move the ends off the screen
		addeq	x1,x1,#16		; not the best way to do it, but the smallest...
		b	%BT03

write_tile_sprite_name_bpp
		; on entry: r5 = bpp to add to the end of the sprite name
		;	    r7 = ptr to end of base sprite name
		;  on exit: string updated to add bpp to end
		ROUT
		Push	"r0-r2,lr"
		mov	r1,r7
		mov	r0,#'-'
		strb	r0,[r1],#1
		mov	r0,r5
		cmp	r0,#16
		movhi	r2,#'3'
		movhi	r0,#2
		moveq	r2,#'1'
		moveq	r0,#6
		strhsb	r2,[r1],#1
		add	r0,r0,#'0'
		strb	r0,[r1],#1
		mov	r0,#0
		strb	r0,[r1,#0]
		Pull	"r0-r2,pc"

tile		DCB	"tile"

get_base_tile_sprite_name
		ROUT
		; on entry: r5 = window bg colour
		;	    r6 = ptr to memory block to put sprite name in
		;  on exit: memory at sp updated to contain the sprite name
		;	    r7 = ptr to terminating NUL
		Push	"r0,lr"
		mov	r7,r6				; r7 = ptr to memory to hold name
		ldr	r0,tile
		str	r0,[r7],#4
		mov	r0,#'_'
		strb	r0,[r7],#1			; now contains 'tile_

		teq	r5,#16
		moveq	r0,#'m'
		streqb	r0,[r7],#1
		beq	%F00				; it's a menu, so now 'tile_m'

		cmp	r5,#10
		movhs	r0,#'1'
		strhsb	r0,[r7],#1			; >= to 10 so put in the 1 'tile_1'
		addhs	r0,r5,#'0'-10			; and set r0 to the second character of the number
		addlo	r0,r5,#'0'			; else r0 = the single digit number
		strb	r0,[r7],#1

00		mov	r0,#0				; finished, so terminate the name
		strb	r0,[r7,#0]

		Pull	"r0,pc"

get_tile_sprite_info
;	on entry:	r1 = sprite area pointer
;			r2 = sprite pointer
;			r8 = ptr to tile info block
;	one exit:       block at r8 filled in
;                       or V set for error
		Push	"r0-r4,lr"

		str	r1,[r8,#TileInfo_SpriteAreaPtr]
		str	r2,[r8,#TileInfo_SpritePtr]

		str	r1,thisCBptr
		str	r2,spritename
		mov	r0,#0
		str	r0,lengthflags
		bl	cachespritedata
		movvs	r0,#-1
		strvs	r0,[r8,#TileInfo_SpritePtr]
		Pull	"r0-r4,pc",VS

		ldr	r0,sprite_log2px
		mov	r3,r3,LSL r0
		str	r3,[r8,#TileInfo_Width]
		ldr	r0,sprite_log2py
		mov	r4,r4,LSL r0
		str	r4,[r8,#TileInfo_Height]

		ldrb	r0,sprite_needsfactors
		teq	r0,#0

		moveq	r0,#-1						; if the scale factors are not needed then the first one is -1

		adrne	r14,sprite_factors
		ldmneia	r14,{r0-r3}

		add	r14,r8,#TileInfo_ScaleFactors
		stmia	r14,{r0-r3}

		ldr	r0,pixtable_at
		str	r0,[r8,#TileInfo_TranslationTablePtr]
		mov	r0,#0
		str	r0,pixtable_at

		Pull	"r0-r4,pc"

find_tile_sprite
;	on entry:	r6 = ptr to sprite name
;			r8 = ptr to info block to fill in
;	on exit:	block at r8 updated
;			or V set if sprite could not be found
		ROUT
		Push	"r0-r3,lr"

		DebugS	tiling,"Looking for sprite : ",r6
		b	%FT02

		ldr	r0,list_at
		teq	r0,#0				; if the cached sprite list does not exist
		beq	%FT02				; do the lookup the slow way

		str	r6,spritename
		bl	getspriteaddr
		ldrvc	r1,baseofsprites

00		movvs	r2,#-1
		strvs	r2,[r8,#TileInfo_SpritePtr]
		Pull	"r0-r3,pc",VS

01
                Debug	tiling,"Sprite found at :",r1,r2
		bl	get_tile_sprite_info

		Pull	"r0-r3,pc"

02		mov     r0,#SpriteReason_SelectSprite :OR: 256
      	    [ SpritePriority
        	ldr     r1,baseofhisprites
      	    |
       	 	ldr     r1,baseofsprites
      	    ]
		mov	r2,r6
		mov	r3,sp
        	swi     XOS_SpriteOp
		mov	r3,sp
        	bvc     %BT01

        	mov     r0,#SpriteReason_SelectSprite :OR: 256
      	    [ SpritePriority
        	ldr     r1,baseoflosprites
            |
        	ldr     r1,baseofromsprites
            ]
		mov	r2,r6
		mov	r3,sp
        	swi     XOS_SpriteOp
		mov	r3,sp
        	bvc     %BT01

		b	%BT00

find_tile_sprite_all_depths
;	on entry:	r5 = window bg colour
;			r6 = ptr to memory block rto put sprite name in
;			r7 = ptr to end of tile_## string
;			r8 = ptr to tile info block to fill in
;			stack contains base sprite name
;	on exit:	block at r8 updated
;			or V set if no sprite could be found
		ROUT
		Push	"r5,lr"

		ldr	r5,log2bpp
		mov	r14,#1
		mov	r5,r14,LSL r5			; r6 = bpp of current screen mode

00		bl	write_tile_sprite_name_bpp
		bl	find_tile_sprite
		Pull	"r5,pc",VC

		mov	r5,r5,LSR #1
		cmp	r5,#8
		bhs	%BT00

		mov	r5,#0
		strb	r5,[r7,#0]			; failed to find any variant of the sprite so try the default
		bl	find_tile_sprite

		Pull	"r5,pc"

get_tile_sprite	ROUT
		; on entry: r5 = window bg colour
		; 	    r8 = ptr to sprite info block to fill in
		;  on exit: block at r8 updated
		;	    V set if sprite not found
		Push	"r0-r7,lr"

00		ldr	r0,[r8,#TileInfo_SpritePtr]
		cmp	r0,#0
                beq     %FT01				; if sprite pointer is != 0 then the sprite has already been
                cmp     r0,#-1
		Pull	"r0-r7,pc",NE			; if not 0 or -1 then return now with V clear
		cmn     r0,#1:SHL:31
		Pull    "r0-r7,pc"			; if it is -1 then return with V set to cause the screen to just
							; be cleared
01
		mov	r0,#161				; check if tiling is disabled in CMOS
		mov	r1,#&8C
		swi	XOS_Byte
		tst	r2,#128
		SETV	NE
		movvs	r0,#-1
		strvs	r0,[r8,#TileInfo_SpritePtr]
		Pull	"r0-r7,pc",VS

		sub	sp,sp,#16

		mov	r6,sp
		bl	get_base_tile_sprite_name
		DebugS	tiling,"Base sprite name : ",r6
		bl	find_tile_sprite_all_depths

		add	sp,sp,#16

		Pull	"r0-r7,pc"

tile_sprite_fill_area
		ROUT
		; on entry: r8  = ptr to sprite info block

		Push	"r0-r11,lr"

		mov	r11,r8

		ldr	x0,[handle,#w_wax0]
		ldr	r0,[handle,#w_scx]
		ldr	r3,[r11,#TileInfo_Width]
		DivRemS	x1,r0,r3,r5
		sub	x0,x0,r0		; x0 = x tiling start point

		ldr	y1,[handle,#w_way1]
		ldr	r0,[handle,#w_scy]
		ldr	r4,[r11,#TileInfo_Height]
		DivRemS	x1,r0,r4,r5
		sub	y1,y1,r0		; y1 = y tiling start point

                adr	r14,clipx0
		ldmia	r14,{r0,y0,x1,r14}

		sub	y0,y0,#1
		sub	y0,y0,r4		; move min y down one whole tile

		sub	r0,r0,#1
		add	x1,x1,#1
		add	r14,r14,#1

00		cmp	y1,r14			; get y1 inside clipping rectangle
		subgt	y1,y1,r4
		bgt	%BT00

01		cmp	x0,r0			; get x0 inside clipping rectangle
		addlt	x0,x0,r3
		blt	%BT01

		sub	x0,x0,r3		; move it back over the left edge of the window

		mov	r0,#SpriteReason_PutSpriteScaled+512
		ldr	r1,[r11,#TileInfo_SpriteAreaPtr]
		ldr	r2,[r11,#TileInfo_SpritePtr]
		mov	r5,#0

		mov	r10,r4			; r10 = tile height
		mov	r4,y1
		mov	r9,r3			; r9 (y1) = tile width

02		mov	r3,x0			; r3 = start x pos
03		bl	plot_tile
		add	r3,r3,r9		; move right one tile
		cmp	r3,x1			; if more tiles on right
		blt	%BT03			; keep going
		sub	r4,r4,r10		; move down one tile
		cmp	r4,y0			; if more tiles below
		bgt	%BT02			; keep going

		Pull	"r0-r11,pc"

plot_tile	ROUT
;	on entry:	r0,r1,r2 - as for OS_SpriteOp 52
;			r3 = x coord
;			r4 = y coord
;			r5 = plot action
;	on exit:	r0-r4 preserved
		Push	"r6,r7,lr"
		ldr	r6,[r11,#TileInfo_ScaleFactors + 0]
		cmp	r6,#-1
		moveq	r6,#0
		addne	r6,r11,#TileInfo_ScaleFactors
		ldr	r7,[r11,#TileInfo_TranslationTablePtr]
		swi	XOS_SpriteOp
		Pull	"r6,r7,pc"

reset_all_tiling_sprites ROUT
		; on entry R0 = the value to write to all tile sprite pointers
		; all tile sprite pointers are updated and all translation tables freed
		Push	"r0-r4,lr"

		mov	r1,r0
		Debug	tiling, "Reset tiling to", r1

		adrl	r3,tile_sprites
		add	r4,r3,#TileInfo * 18				; 16 background tiles + menu tile + temp tile

00		str	r1,[r3,#TileInfo_SpritePtr]			; set the sprite pointer

		ldr	r2,[r3,#TileInfo_TranslationTablePtr]
		teq	r2,#0						; if the table is non zero then free it
		movne	r0,#ModHandReason_Free
		blne	XROS_Module

		mov	r2,#0
		str	r2,[r3,#TileInfo_TranslationTablePtr]		; the table no longer exists so set the pointer to 0

		add	r3,r3,#TileInfo					; move on to the next one
		cmp	r3,r4
		bcc	%BT00

		Pull	"r0-r4,pc"                                      ; exit with V clear

		END