; WatchTV, written by Vincent Lefvre
; Freeware.

; $Id: watchtv 1.7 2001/08/11 01:01:29 vlefevre Exp $

; New version with allocated SWI chunk for the TV module.

		GET	h:RegNames
		GET	h:SWINames

STACKSIZE	EQU	40
SZ		EQU	30
DX		EQU	16
DY		EQU	12
EX		EQU	DX*SZ
EY		EQU	DY*SZ
FORMAT		EQU	1
YMAX		EQU	288
DVOL		EQU	&11

SCRN		RN	R7			;Screen memory address.
SX		RN	R8			;Size X.
SY		RN	R9			;Size Y.
DB		RN	R10			;Double pixel mode.
MX		RN	R11			;Volume (b0) / mute (b1).
MF		RN	R12			;Miller algorithm flag.

REGS		RLIST	{R7,R9-R12}

; If (unsigned) MF < (unsigned) DB, Miller algorithm is used.
; Otherwise:
; DB = 0: normal.
;    > 0: double Y.
;    < 0: double Y and double X.

		AREA	WatchTV, CODE

mask		DCD	2_1111100000111110000011111
watchtv		DCB	"WatchTV",0
modesel		DCD	1,EX,EY,4,-1,4,0,5,0,-1
vduvar		DCD	149,-1

		ENTRY

		ADR	SP, stack+STACKSIZE	;Stack end.
		STR	LR, [SP, #-4]!		;Save return address.
		MOV	R0, #0
		ADR	R1, modesel
		SWI	OS_ScreenMode		;Screen mode: EXxEYx32k.
		MOV	R0, #4
		MOV	R1, #2			;Arrows: &8C-&8F.
		SWI	OS_Byte			;Disable cursor editing.

		MOV	R0, #221
loop_osbyte	SUB	R1, R0, #221-8		;R1: 8 --> 15.
		BIC	R1, R1, #4		;R1: 8 --> 11.
		MOV	R1, R1, LSL #4		;R1: &80, &90, &A0 or &B0.
		MOV	R2, #0
		SWI	OS_Byte			;Function keys F1-F10...
		ADD	R0, R0, #1
		CMP	R0, #228
		BLS	loop_osbyte		;Loop (221 <= R0 <= 228).

		SWI	OS_RemoveCursors	;Remove the text cursor.
		ADR	R0, vduvar
		ADD	R1, SP, #4
		SWI	OS_ReadVduVariables
		LDR	SCRN, [R1]		;Screen memory address.

		MOV	R0, #0
		MOV	R1, #FORMAT
		MOV	R2, #0
		ADR	R3, watchtv
		SWI	MultiMedia_Initialise	;Init the Eagle card.

		MOV	R0, #229
		MOV	R1, #1
		SWI	OS_Byte			;Disable escape conditions.

		MOV	R0, #4
		SWI	XScreenBlanker_Control	;Current screenblanker delay.
		STR	R1, [SP, #-4]!		;Save screenblanker delay.
		MOV	R0, #3
		MOV	R1, #0
		SWI	XScreenBlanker_Control	;Disable screenblanker.

		MOV	SX, #EX			;Size X.
		MOV	SY, #EY			;Size Y.

		MOV	R0, #15
		MOV	R1, #-1
		SWI	MultiMedia_Mixer
		MOV	MX, R1, LSL #8
		MOV	R0, #6
		MOV	R1, #-1
		SWI	MultiMedia_Mixer
		MOV	R2, R1
		MOV	R0, #7
		MOV	R1, #-1
		SWI	MultiMedia_Mixer
		ADD	R1, R1, R2
		ORR	MX, MX, R1, LSR #1
		BL	set_volume
		MOV	MF, #0

doublepix	MOV	DB, #-1			;Double pixel mode.
setframestore	CMP	SY, #YMAX		;If SY >= YMAX and DB == 0,
		ORRCS	DB, DB, #1		;then DB = 1.
		CMP	DB, #0			;SetFramestore...
		RSBGTS	R1, DB, MF, LSL #31
		MOVPL	R0, SX
		MOVMI	R0, SX, LSR #1
		MOVEQ	R1, SY, LSL #1
		MOVNE	R1, SY
		MOV	R2, #FORMAT
		MOV	R3, #&00FFFFFF
		SWI	MultiMedia_SetFramestore
next_frame	SWI	OS_ReadMonotonicTime
		ADD	R1, R0, #4		;4 cs.
wait		SWI	OS_ReadMonotonicTime
		CMP	R0, R1
		BMI	wait

loop		CMP	DB, #0			;Grab and display a frame...
		RSBGTS	R1, DB, MF, LSL #31
		MOVPL	R0, SX
		MOVMI	R0, SX, LSR #1
		MOVEQ	R1, SY
		MOVNE	R1, SY, LSR #1
		MOV	R2, #FORMAT
		ADR	R3, stack+STACKSIZE
		SWI	MultiMedia_GrabFrame
		RSB	R3, SY, #EY
		MOV	R2, #EX
		MLA	R1, R2, R3, SCRN
		ADR	R0, stack+STACKSIZE
		RSB	R4, SX, #EX
		MOV	R5, SY
		ADD	R1, R1, R4

; R0: source.
; R1: destination.
; R4: dest size X - source size X.
; R5: size Y (source).

		CMP	DB, MF
		BHI	miller			;If UDB > UMF, use Miller algo.
		TEQ	DB, #0
		BMI	disp3
		BNE	disp2

disp1		MOV	R2, SX			;Display: normal.
loop1x		LDR	R3, [R0], #4
		STR	R3, [R1], #4
		SUBS	R2, R2, #2
		BNE	loop1x
		ADD	R1, R1, R4, LSL #1
		SUBS	R5, R5, #1
		BNE	disp1
		B	read_key

disp2		MOV	R2, SX			;Display: double Y.
loop2x		LDR	R3, [R0], #4
		STR	R3, [R1, #EX<<1]
		STR	R3, [R1], #4
		SUBS	R2, R2, #2
		BNE	loop2x
		ADD	R1, R1, R4, LSL #1
		ADD	R1, R1, #EX<<1
		SUBS	R5, R5, #2
		BNE	disp2
		B	read_key

disp3		MOV	R2, SX			;Display: double Y and double X.
loop3x		LDR	R3, [R0], #4
		MOV	R6, R3, LSR #16
		MOV	R3, R3, LSL #16
		ORR	R3, R3, R3, LSR #16
		STR	R3, [R1, #EX<<1]
		ORR	R6, R6, R6, LSL #16
		STR	R6, [R1, #EX<<1+4]
		STMIA	R1!, {R3,R6}
		SUBS	R2, R2, #4
		BNE	loop3x
		ADD	R1, R1, R4, LSL #1
		ADD	R1, R1, #EX<<1
		SUBS	R5, R5, #2
		BNE	disp3
		B	read_key

miller		STMFD	SP!, REGS
		LDR	R12, mask
		SUB	R5, R5, #2
mloopy		LDR	R11, [R0, SX]
		LDR	R10, [R0]
		AND	R3, R11, R12, LSR #10
		AND	R9, R11, #2_1111100000
		ADD	R3, R3, R9, LSL #15	;R3: left bottom G_R_B.
		AND	R2, R10, R12, LSR #10
		AND	R9, R10, #2_1111100000
		ADD	R2, R2, R9, LSL #15	;R2: left top G_R_B.
		SUB	R5, R5, SX, LSL #16
mloopx1		LDR	R11, [R0, SX]
		LDR	R10, [R0], #2
		AND	R7, R11, R12, LSR #10
		AND	R9, R11, #2_1111100000
		ADD	R7, R7, R9, LSL #15	;R7: right bottom G_R_B.
		AND	R6, R10, R12, LSR #10
		AND	R9, R10, #2_1111100000
		ADD	R6, R6, R9, LSL #15	;R6: right top G_R_B.
		ADD	R11, R2, R7		;R11: \ diagonal.
		ADD	R10, R3, R6		;R10: / diagonal.
		ADD	R9, R10, R11		;R9: sum.
		ADD	R11, R9, R11, LSL #1	;R11: \ (1,3,3,1).
		ADD	R10, R9, R10, LSL #1	;R10: / (1,3,3,1).
		ADD	R3, R11, R3, LSL #3	;R3  = 9-bit dest left bottom.
		ADD	R2, R10, R2, LSL #3	;R2  = 9-bit dest left top.
		ADD	R11, R11, R6, LSL #3	;R11 = 9-bit dest right top.
		ADD	R10, R10, R7, LSL #3	;R10 = 9-bit dest right bottom.
		AND	R3, R12, R3, LSR #4	;R3  = 5-bit dest left bottom.
		AND	R2, R12, R2, LSR #4	;R2  = 5-bit dest left top.
		AND	R11, R12, R11, LSR #4	;R11 = 5-bit dest right top.
		AND	R10, R12, R10, LSR #4	;R10 = 5-bit dest right bottom.
		ADD	R3, R3, R3, LSL #15	;Video encoding...
		ADD	R2, R2, R2, LSL #15
		MOV	R3, R3, LSR #15
		MOV	R2, R2, LSR #15
		ADD	R10, R10, R10, LSR #15
		ADD	R11, R11, R11, LSR #15
		ADD	R10, R3, R10, LSL #16
		ADD	R11, R2, R11, LSL #16
		STR	R10, [R1, #EX<<1]	;Store bottom (2 pixels).
		MOV	R3, R7			;Right bottom --> left bottom.
		STR	R11, [R1], #4		;Store top (2 pixels).
		MOV	R2, R6			;Right top --> left top.
		ADDS	R5, R5, #2<<16
		BMI	mloopx1
		ADD	R1, R1, R4, LSL #1
		ADD	R1, R1, #EX<<1
		SUBS	R5, R5, #2
		BNE	mloopy
		MOV	R0, #0			;Clear the last double-line...
		MOV	R5, SX
mloopx2		STR	R0, [R1, #EX<<1]
		STR	R0, [R1], #4
		SUBS	R5, R5, #2
		BNE	mloopx2
		LDMFD	SP!, REGS

read_key	MOV	R0, #129		;Read the keyboard...
		MOV	R1, #0
		MOV	R2, #0
		SWI	OS_Byte
		TEQ	R2, #&1B
		BEQ	exit			;Exit if escape condition.
		TEQ	R2, #0
		BNE	loop			;Loop if no key pressed.
		TEQ	R1, #'Q'
		TEQNE	R1, #'q'
		TEQNE	R1, #17
		TEQNE	R1, #27
		BEQ	exit			;Exit if Q, q, ctrl-Q or Esc.
		TEQ	R1, #'-'
		BEQ	key_decr
		TEQ	R1, #'+'
		BEQ	key_incr
		TEQ	R1, #'1'
		TEQNE	R1, #'2'
		SUBEQ	DB, R1, #'1'
		BEQ	setframestore
		TEQ	R1, #'3'
		BEQ	doublepix
		TEQ	R1, #'4'
		TEQNE	R1, #'5'
		SUBEQ	MF, R1, #'4'
		BEQ	setframestore
		TEQ	R1, #'6'
		MOVEQ	MF, #-1
		BEQ	setframestore
		TEQ	R1, #'*'
		BEQ	toggle_mute
		TEQ	R1, #&8E		;Cursor up.
		BEQ	decr_volume
		TEQ	R1, #&8F		;Cursor down.
		BEQ	incr_volume
		SUBS	R0, R1, #&80		;Keycode <= &80 or
		RSBHIS	R1, R0, #&40		;Keycode >= &C0 ?
		BLS	loop			;then branch.
		MOV	R1, R0, LSR #4		;R1 = R0 DIV 16 (0..3).
		ANDS	R0, R0, #&F		;R0 = R0 MOD 16.
		BEQ	loop
		CMP	R0, #10
		BHI	loop			;Branch if R0 < 1 or R0 > 10.
		ADD	R0, R0, R1, LSL #3	;\ Add
		ADD	R0, R0, R1, LSL #1	;/ 10*R1.
		SWI	XTV_Channel		;Channel R0 (1..40).
		B	next_frame

toggle_mute	EOR	MX, MX, #&FF00		;Toggle mute status...
		MOV	R0, #15
		MOV	R1, MX, LSR #8
		SWI	MultiMedia_Mixer
		B	loop

decr_volume	ANDS	R0, MX, #&FF		;Decrease the volume...
		BEQ	loop
		SUBS	R0, R0, #DVOL
		SUBPL	MX, MX, #DVOL
		BICMI	MX, MX, #&FF
		B	new_volume

incr_volume	MOV	R0, MX, LSL #24		;Increase the volume...
		TEQ	R0, #&FF000000
		BEQ	loop
		ADDS	R0, R0, #DVOL<<24
		ADDCC	MX, MX, #DVOL
		ORRCS	MX, MX, #&FF
new_volume	ADR	LR, loop

set_volume	MOV	R5, LR			;Set the volume...
		MOV	R0, #6
		AND	R1, MX, #&FF
		SWI	MultiMedia_Mixer
		MOV	R0, #7
		AND	R1, MX, #&FF
		SWI	MultiMedia_Mixer
		MOV	PC, R5

key_decr	CMP	SX, #DX			;Decrease image size...
		BEQ	loop
		RSB	R3, SY, #EY
		MOV	R2, #EX
		MLA	R1, R2, R3, SCRN
		RSB	R4, SX, #EX
		MOV	R0, #0
		ADD	R1, R1, R4
		BL	decr_cltopbot
		MOV	R2, #0
		MOV	R3, #0
		MOV	R6, #0
		SUB	R5, SY, #DY
decr_loop2	STMIA	R1, {R0,R2,R3,R6}
		ADD	R1, R1, SX, LSL #1
		STMDB	R1, {R0,R2,R3,R6}
		ADD	R1, R1, R4, LSL #1
		SUBS	R5, R5, #1
		BNE	decr_loop2
		BL	decr_cltopbot
		SUB	SX, SX, #DX
		SUB	SY, SY, #DY
		B	setframestore

decr_cltopbot	MOV	R5, #DY
decr_loop1y	MOV	R2, SX
decr_loop1x	STR	R0, [R1], #4
		SUBS	R2, R2, #2
		BNE	decr_loop1x
		ADD	R1, R1, R4, LSL #1
		SUBS	R5, R5, #2
		BNE	decr_loop1y
		MOV	PC, LR

key_incr	CMP	SX, #EX			;Increase image size...
		BEQ	loop
		ADD	SX, SX, #DX
		ADD	SY, SY, #DY
		B	setframestore

; Exit...

exit		LDR	R1, [SP], #4		;Screenblanker delay in seconds.
		MOV	R2, #100
		MOV	R0, #3
		MUL	R1, R2, R1		;Delay in centiseconds.
		SWI	XScreenBlanker_Control	;Restore screenblanker delay.
		MOV	R0, #125
		SWI	OS_Byte			;Sets an escape condition.
		LDR	PC, [SP], #4		;(Should not be executed.)

stack		%	0

		END
