	.include	"global.s"

	.globl	.init_vram
	.globl	.copy_vram

	.SOLID	=   0x00
	.OR	=   0x01
	.XOR	=   0x02
	.AND	=   0x03

	.area	_HEADER (ABS)

	.org	.MODE_TABLE+4*.G_MODE
	JP	.gmode

	.module	Drawing

	.area	_CODE

	;; Enter graphic mode
.gmode::
	DI			; Disable interrupts

	;; Turn the screen off
	LDH	A,(.LCDC)
	BIT	7,A
	JR	Z,1$

	;; Turn the screen off
	CALL	.display_off
1$:
	LD	HL,#0x8000+0x10*0x10
	LD	DE,#0x1800-0x18*0x10
	LD	B,#0x00
	CALL	.init_vram	; Init the charset at 0x8000

	;; Install interrupt routines
	LD	BC,#.vbl
	CALL	.add_VBL
	LD	BC,#.lcd
	CALL	.add_LCD

	LD	A,#72		; Set line at which LCD interrupt occurs
	LDH	(.LYC),A

	LD	A,#0b01000100	; Set LCD interrupt to occur when LY = LCY
	LDH	(.STAT),A

	LDH	A,(.IE)
	OR	#0b00000010	; Enable LCD interrupt
	LDH	(.IE),A

	;; (9*20) = 180 tiles are used in the upper part of the screen
	;; (9*20) = 180 tiles are used in the lower part of the screen
	;; => We have 24 tiles free
	;; We keep 16 at 0x8000->0x80FF, and 8 at 0x9780->97FF

	LD	HL,#0x9800
	LD	A,#0x10		; Keep 16 tiles free
	LD	BC,#12		; 12 unused columns
	LD	E,#18		; 18 lines
2$:
	LD	D,#20		; 20 used columns
3$:
	LD	(HL+),A
	INC	A
	DEC	D
	JR	NZ,3$
	ADD	HL,BC
	DEC	E
	JR	NZ,2$

	;; Turn the screen on
	LDH	A,(.LCDC)
	OR	#0b10010001	; LCD		= On
				; BG Chr	= 0x8000
				; BG		= On
	AND	#0b11110111	; BG Bank	= 0x9800
	LDH	(.LCDC),A

	LD	A,#.G_MODE
	LD	(.mode),A

	EI			; Enable interrupts

	RET

.vbl::
	LDH	A,(.LCDC)
	OR	#0b00010000	; Set BG Chr to 0x8000
	LDH	(.LCDC),A

	LD	A,#72		; Set line at which LCD interrupt occurs
	LDH	(.LYC),A

	RET

.lcd::
1$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,1$

	LDH	A,(.LCDC)
	AND	#0b11101111	; Set BG Chr to 0x8800
	LDH	(.LCDC),A

	RET

	;; Draw a full-screen image at (BC)
.draw_image::
	LD	HL,#0x8000+0x10*0x10
	LD	DE,#0x1680
	CALL	.copy_vram	; Move the charset
	RET

	;; Replace tile data at (B,C) with data at DE and store old value at HL
.switch_data::
	PUSH	DE		; Save src
	PUSH	HL		; Save dst
	LD	DE,#0x8000+0x10*0x10
	LD	L,B
	SLA	L
	SLA	L
	SLA	L
	LD	H,#0x00
	ADD	HL,HL
	ADD	HL,DE
	LD	D,H
	LD	E,L

	LD	HL,#.y_table
	SLA	C
	SLA	C
	SLA	C
	LD	B,#0x00
	ADD	HL,BC
	ADD	HL,BC
	LD	B,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,B
	ADD	HL,DE

	LD	B,H		; BC = src
	LD	C,L
	POP	HL		; HL = dst
	PUSH	BC		; Save dst
	LD	A,H
	OR	L
	JR	Z,1$
	LD	DE,#0x10
	CALL	.copy_vram
1$:
	POP	HL		; HL = dst
	POP	BC		; BC = src
	LD	DE,#0x10
	CALL	.copy_vram

	RET

	;; Draw a point at (B,C) with color D and mode E
.plot::
	PUSH	DE		; Save color and mode
	LD	DE,#0x8000+0x10*0x10
	LD	A,B
	LD	L,B
	SRL	L
	SRL	L
	SRL	L
	RLC	L
	RLC	L
	RLC	L
	LD	H,#0x00
	ADD	HL,HL
	ADD	HL,DE
	LD	D,H
	LD	E,L

	LD	HL,#.y_table
	LD	B,#0x00
	ADD	HL,BC
	ADD	HL,BC
	LD	B,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,B
	ADD	HL,DE

	AND	#7
	ADD	#0x10		; Table of bits is located at 0x0010
	LD	E,A
	LD	D,#0x00
	LD	A,(DE)
	LD	B,A
	CPL
	LD	C,A

	POP	DE		; Restore color and mode
	LD	A,E
	CP	#.SOLID
	JR	NZ,10$
	;; Solid
1$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,1$

	LD	A,(HL)
	AND	C
	BIT	0,D
	JR	Z,2$
	OR	B
2$:
	LD	(HL+),A
3$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,3$

	LD	A,(HL)
	AND	C
	BIT	1,D
	JR	Z,4$
	OR	B
4$:
	LD	(HL),A
	RET

10$:
	CP	#.XOR
	JR	NZ,20$
	;; Xor
	BIT	0,D
	JR	Z,12$
11$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,11$

	LD	A,(HL)
	XOR	B
	LD	(HL+),A
12$:
	BIT	1,D
	RET	Z
13$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,13$

	LD	A,(HL)
	XOR	B
	LD	(HL),A
	RET

20$:
	CP	#.OR
	JR	NZ,30$
	;; Or
	BIT	0,D
	JR	Z,22$
21$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,21$

	LD	A,(HL)
	OR	B
	LD	(HL+),A
22$:
	BIT	1,D
	RET	Z
23$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,23$

	LD	A,(HL)
	OR	B
	LD	(HL),A
	RET

30$:
	CP	#.AND
	RET	NZ
	;; And
	BIT	0,D
	JR	NZ,32$
31$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,31$

	LD	A,(HL)
	AND	C
	LD	(HL+),A
32$:
	BIT	1,D
	RET	NZ
33$:
	LDH	A,(.STAT)
	BIT	1,A
	JR	NZ,33$

	LD	A,(HL)
	AND	C
	LD	(HL),A
	RET

	;; ************************************************************
	;; Draw a line from x1,y1 (B,C) to x2,y2 (D,E) with color H and mode L
	;
	; BC: current point
	.area	_BSS
.a_diff:
	.ds	0x01
.a_xy:
	.ds	0x01
.sx:
	.ds	0x01
.sy:
	.ds	0x01
.line_color:
	.ds	0x01
.line_mode:
	.ds	0x01

	.area	_CODE
.line:
	LD	A,H
	LD	(.line_color),A
	LD	A,L
	LD	(.line_mode),A
	; ax = ABS(x2-x1)<<1; sx = SGN(x2-x1);
	;
	LD	A,D
	SUB	B			; A=x2-x1
	JR	C,1$
	; x2-x1 >= 0
					; A=ABS(x2-x1)
	LD	H,A			; Backup ABS(x2-x1) in H
	LD	A,#0x01			; A=SGN(x2-x1)=1
	JR	2$
1$:	; x2-x1 < 0
	CPL				; A=ABS(x2-x1)
	INC	A
	LD	H,A			; Backup ABS(x2-x1) in H
	LD	A,#0xFF			; A=SGN(x2-x1)=-1
2$:
	LD	(.sx),A

	; ay = ABS(y2-y1)<<1; sy = SGN(y2-y1);
	;
	LD	A,E
	SUB	C			; A=y2-y1
	JR	C,3$
	; y2-y1 >= 0
					; A=ABS(y2-y1)
	LD	L,A			; Backup ABS(y2-y1) in L
	LD	A,#0x01			; A=SGN(y2-y1)=1
	JR	4$
3$:	; y2-y1 < 0
	CPL				; A=ABS(y2-y1)
	INC	A
	LD	L,A			; Backup ABS(y2-y1) in L
	LD	A,#0xFF			; A=SGN(y2-y1)=-1
4$:
	LD	(.sy),A

	; if(ax>ay)
	;
	LD	A,L
	SUB	H			; A=ay>>1-ax>>1
	JR	NC,7$

	; ax>ay (x dominant)
	LD	A,H
	SUB	L			; A=ax>>1-ay>>1
 	ADD	A
	LD	(.a_diff),A		; a_diff=ax-ay
	LD	A,L
	ADD	A
	LD	(.a_xy),A		; a_xy=ay
	; d = (ay<<1)-ax;
	;
	LD	A,L
	ADD	A
	SUB	H			; A=ay-(ax>>1)=(ay<<1)-ax=(L<<1)-H
	LD	L,A			; HL=d
	LD	A,#0x00
	SBC	A
	LD	H,A

	; for(;;)
	;
5$:
	; plot(x,y);
	;
	CALL	.line_plot
	; if(x==x2) return;
	;
	LD	A,D
	CP	B
	RET	Z
	; if(d>=0)
	;
	LD	A,H
	AND	#0x80
	JR	NZ,6$
	; d>=0
	; x+=sx;
	;
	LD	A,(.sx)
	ADD	B
	LD	B,A
	; y+=sy;
	;
	LD	A,(.sy)
	ADD	C
	LD	C,A
	; d-=(ax-ay);
	;
	LD	A,(.a_diff)
	LD	H,A
	LD	A,L
	SUB	H
	LD	L,A
	LD	A,#0x00
	SBC	A
	LD	H,A
	JR	5$
6$:	; d<0
	; x+=sx;
	;
	LD	A,(.sx)
	ADD	B
	LD	B,A
	; d+=ay;
	;
	LD	A,(.a_xy)
	ADD	L
	LD	L,A
	LD	A,H
	ADC	#0x00
	LD	H,A
	JR	5$

7$:	; ax<=ay (y dominant)
 	ADD	A
	LD	(.a_diff),A		; a_diff=ay-ax
	LD	A,H
	ADD	A
	LD	(.a_xy),A		; a_xy=ax
	; d = (ax<<1)-ay;
	;
	LD	A,H
	ADD	A
	SUB	L			; A=(ax<<1)-ay=ax-(ay>>1)=(H<<1)-L
	LD	L,A			; HL=d
	LD	A,#0x00
	SBC	A
	LD	H,A

	; for(;;)
	;
8$:
	; plot(x,y);
	;
	CALL	.line_plot
	; if(y==y2) return;
	;
	LD	A,E
	CP	C
	RET	Z
	; if(d>=0)
	;
	LD	A,H
	AND	#0x80
	JR	NZ,9$
	; d>=0
	; x+=sx;
	;
	LD	A,(.sx)
	ADD	B
	LD	B,A
	; y+=sy;
	;
	LD	A,(.sy)
	ADD	C
	LD	C,A
	; d-=(ay-ax);
	;
	LD	A,(.a_diff)
	LD	H,A
	LD	A,L
	SUB	H
	LD	L,A
	LD	A,#0x00
	SBC	A
	LD	H,A
	JR	8$
9$:	; d<0
	; y+=sy;
	;
	LD	A,(.sy)
	ADD	C
	LD	C,A
	; d+=ax;
	;
	LD	A,(.a_xy)
	ADD	L
	LD	L,A
	LD	A,H
	ADC	#0x00
	LD	H,A
	JR	8$

	;; ************************************************************
	;; Plot a point at (B,C)
	;; Save registers
	;
.line_plot:
	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	A,(.line_color)
	LD	D,A
	LD	A,(.line_mode)
	LD	E,A
	CALL	.plot
	POP	HL
	POP	DE
	POP	BC
	RET

_plot::
	PUSH	BC

	LD	A,(.mode)
	CP	#.G_MODE
	JR	Z,1$
	CALL	.gmode
1$:
	LDA	HL,4(SP)	; Skip return address and registers
	LD	B,(HL)		; B = x
	INC	HL
	LD	C,(HL)		; C = y
	INC	HL
	LD	D,(HL)		; D = color
	INC	HL
	LD	E,(HL)		; E = mode

	CALL	.plot

	POP	BC
	RET

_switch_data::
	PUSH	BC

	LD	A,(.mode)
	CP	#.G_MODE
	JR	Z,1$
	CALL	.gmode
1$:
	LDA	HL,4(SP)	; Skip return address and registers
	LD	B,(HL)		; B = x
	INC	HL
	LD	C,(HL)		; C = y
	INC	HL
	LD	E,(HL)		; DE = src
	INC	HL
	LD	D,(HL)
	INC	HL
	LD	A,(HL+)		; HL = dst
	LD	H,(HL)
	LD	L,A

	CALL	.switch_data

	POP	BC
	RET

_line::
	PUSH	BC

	LD	A,(.mode)
	CP	#.G_MODE
	JR	Z,1$
	CALL	.gmode
1$:
	LDA	HL,4(SP)	; Skip return address and registers
	LD	B,(HL)		; B = x1
	INC	HL
	LD	C,(HL)		; C = y1
	INC	HL
	LD	D,(HL)		; D = x2
	INC	HL
	LD	E,(HL)		; E = y2
	INC	HL
	LD	A,(HL+)		; H = color
	LD	L,(HL)		; L = mode
	LD	H,A

	CALL	.line

	POP	BC
	RET

_draw_image::
	PUSH	BC

	LD	A,(.mode)
	CP	#.G_MODE
	JR	Z,1$
	CALL	.gmode
1$:
	LDA	HL,4(SP)	; Skip return address and registers
	LD	C,(HL)		; HL = data
	INC	HL
	LD	B,(HL)

	CALL	.draw_image

	POP	BC
	RET

_clear::			; Clear the graphics screen
	LD	HL,#0x8000+0x10*0x10
	LD	DE,#0x1680
1$:
	LDH	A,(.STAT)
	AND	#0x02
	JR	NZ,1$

	LD	(HL+),A		; A is already zero
	DEC	DE
	LD	A,D
	OR	E
	JR	NZ,1$
	RET

	.area	_DATA

.y_table::
	.word	0x0000,0x0002,0x0004,0x0006,0x0008,0x000A
	.word	0x000C,0x000E,0x0140,0x0142,0x0144,0x0146
	.word	0x0148,0x014A,0x014C,0x014E,0x0280,0x0282
	.word	0x0284,0x0286,0x0288,0x028A,0x028C,0x028E
	.word	0x03C0,0x03C2,0x03C4,0x03C6,0x03C8,0x03CA
	.word	0x03CC,0x03CE,0x0500,0x0502,0x0504,0x0506
	.word	0x0508,0x050A,0x050C,0x050E,0x0640,0x0642
	.word	0x0644,0x0646,0x0648,0x064A,0x064C,0x064E
	.word	0x0780,0x0782,0x0784,0x0786,0x0788,0x078A
	.word	0x078C,0x078E,0x08C0,0x08C2,0x08C4,0x08C6
	.word	0x08C8,0x08CA,0x08CC,0x08CE,0x0A00,0x0A02
	.word	0x0A04,0x0A06,0x0A08,0x0A0A,0x0A0C,0x0A0E
	.word	0x0B40,0x0B42,0x0B44,0x0B46,0x0B48,0x0B4A
	.word	0x0B4C,0x0B4E,0x0C80,0x0C82,0x0C84,0x0C86
	.word	0x0C88,0x0C8A,0x0C8C,0x0C8E,0x0DC0,0x0DC2
	.word	0x0DC4,0x0DC6,0x0DC8,0x0DCA,0x0DCC,0x0DCE
	.word	0x0F00,0x0F02,0x0F04,0x0F06,0x0F08,0x0F0A
	.word	0x0F0C,0x0F0E,0x1040,0x1042,0x1044,0x1046
	.word	0x1048,0x104A,0x104C,0x104E,0x1180,0x1182
	.word	0x1184,0x1186,0x1188,0x118A,0x118C,0x118E
	.word	0x12C0,0x12C2,0x12C4,0x12C6,0x12C8,0x12CA
	.word	0x12CC,0x12CE,0x1400,0x1402,0x1404,0x1406
	.word	0x1408,0x140A,0x140C,0x140E,0x1540,0x1542
	.word	0x1544,0x1546,0x1548,0x154A,0x154C,0x154E
