;-------------------------------------------------------------------------------
; ZX X-MAS '19 - PRECALC PROCESSES
;
;       (/&&&/\&\  /%/  \&\  /%/   /%)(#)(&\ /%###&\ /###)  ()/%|  /&&&\
;         /%/  \&\/%/    \&\/%/,--,|#||#||#| |#| |#| |&&\     |#| (&___&)
;        /%/   /%/\&\    /%/\&\'--'|#||#||#| |###|#|  \&&|    |#|    (&&)
;       /&&&/)/%/  \&\  /%/  \&\   |#||#||#| |#| |#| (###/    |#| (&&&&/
;
; Copyright AbaddoN (C)2018-2019
; Code and gfx by: G.o.D. / AbaddoN
; Mzx by: ern0 / AbaddoN
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; Variables, lookup tables

; Memory addresses of KKU text's shifted phases.
KKU_PHASES_ADDR_LOOKUP:
	defw	KKU_PHASES_ADDR
	defs	7*2

; Cosine lookup table for moving KKU gfx left-to-right-to-left
COS_LOOKUP_TABLE:
INCBIN 'cos_lookup_table.bin'
	defb	$FF				; End of lookup table

;-------------------------------------------------------------------------------
SCREEN_WIDTH_BYTES		EQU	$20	; width of screen in bytes
KKU_GFX_X_BYTE_POS		EQU	11	; left position of scrolled KKU text in bytes
KKU_GFX_Y_PX_POS		EQU	84	; top position of scrolled KKU text in px.
KKU_ORIG_GFX_WIDTH_BYTE	EQU	86	; original KKU text gfx line width in byte
KKU_GFX_WIDTH_BYTE		EQU	98	; 688px gfx + 2*48px margin=784px -> 98 bytes
							; one gfx:3136 bytes
							; eight gfx:25088 bytes ($6200)
KKU_HEIGHT_PX			EQU	32	; height of KKU text gfx in pixels
KKU_MARGIN_WIDTH_BYTES	EQU	6	; width of KKU text gfx margin in bytes
KKU_GFX_SIZE_BYTE		EQU	KKU_HEIGHT_PX*KKU_GFX_WIDTH_BYTE
							; ^^^ size of one phase of KKU gfx
KKU_GFX_SIZE1			EQU	1078		; ~1/3rd of KKU gfx
KKU_GFX_SIZE2			EQU	1078		; (must be divided by 1 line = 98)
KKU_GFX_SIZE3			EQU	KKU_GFX_SIZE_BYTE-KKU_GFX_SIZE1-KKU_GFX_SIZE2

; Writes "KELLEMES KARÁCSONYI ÜNNEPEKET!" text into memory with margin on both
; sides and make the 1-7 bit right shifted version of the text.
; Separated process to stay below 30000T time,must be called 120 times (or more)
; Margin with is 6 bytes = 48px
; in:  -
; out: -
; mod: AF,BC,DE,HL
; Code running time: 15500T-24000T
PRECALC_KKU_TEXT:
PCT_Phase:
	ld	a,0
	inc	a
	ld	(PCT_Phase+1),a
	dec	a
	jr	z,PCT_ErasePhase1	; 1: erase KKU text 1st phase's memory area
	dec	a
	jr	z,PCT_ErasePhase2	; 2: erase KKU text 1st phase's memory area
	dec	a
	jr	z,PCT_ErasePhase3	; 3: erase KKU text 1st phase's memory area
	dec	a
	jr	z,PCT_CopyGfx1		; 4: copy original (w/o margins) KKU gfx
	dec	a
	jr	z,PCT_CopyGfx2		; 5: copy original (w/o margins) KKU gfx
	dec	a
	jr	z,PCT_CopyGfx3		; 6: copy original (w/o margins) KKU gfx
	dec	a
	ret	z				; 7: skip
	dec	a
	cp	112				; from 8: 3* copy prev and 13* RR new phase
	ret	nc				; do the above 7 times (8-119)
	jr	PCT_ShiftCopy
PCT_ErasePhase1:
	; clear memory 1 for 0 shifted KKU text
	ld	hl,KKU_PHASES_ADDR
	ld	de,KKU_PHASES_ADDR+1
	ld	(hl),0
	ld	bc,KKU_GFX_SIZE1
	ldir
	ret
PCT_ErasePhase2:
	; clear memory 2 for 0 shifted KKU text
	ld	hl,KKU_PHASES_ADDR+KKU_GFX_SIZE1
	ld	de,KKU_PHASES_ADDR+KKU_GFX_SIZE1+1
	ld	bc,KKU_GFX_SIZE2
	ldir
	ret
PCT_ErasePhase3:
	; clear memory 3 for 0 shifted KKU text
	ld	hl,KKU_PHASES_ADDR+KKU_GFX_SIZE1+KKU_GFX_SIZE2
	ld	de,KKU_PHASES_ADDR+KKU_GFX_SIZE1+KKU_GFX_SIZE2+1
	ld	bc,KKU_GFX_SIZE3-1
	ldir
	ret
PCT_CopyGfx1:
	; Copy 1st pack of KKU text gfx to 1st phase memory address
	ld	hl,KKU_ORIG_TEXT_GFX_ADDR ; gfx source
	ld	de,KKU_PHASES_ADDR+KKU_MARGIN_WIDTH_BYTES
					; gfx destination + left margin
	ld	a,11			; _11_-11-10 lines
	jr	PCT_CopyGfxLoop
PCT_CopyGfx2:
	; Copy 2nd pack of KKU text gfx to 1st phase memory address
	ld	hl,KKU_ORIG_TEXT_GFX_ADDR+(11*KKU_ORIG_GFX_WIDTH_BYTE) ; gfx source
	ld	de,KKU_PHASES_ADDR+KKU_MARGIN_WIDTH_BYTES+(11*KKU_GFX_WIDTH_BYTE)
					; gfx destination + left margin
	ld	a,11			; 11-_11_-10 lines
	jr	PCT_CopyGfxLoop
PCT_CopyGfx3:
	ld	hl,KKU_ORIG_TEXT_GFX_ADDR+(22*KKU_ORIG_GFX_WIDTH_BYTE) ; gfx source
	ld	de,KKU_PHASES_ADDR+KKU_MARGIN_WIDTH_BYTES+(22*KKU_GFX_WIDTH_BYTE)
					; gfx destination + left margin
	ld	a,10			; 11-11-_10_ lines

PCT_CopyGfxLoop:
	ld	bc,KKU_ORIG_GFX_WIDTH_BYTE	; gfx width - margins
	ldir
	ex	de,hl					; skip left and right margin
	ld	bc,2*KKU_MARGIN_WIDTH_BYTES
	add	hl,bc
	ex	de,hl
	dec	a
	jr	nz,PCT_CopyGfxLoop
	ret

PCT_ShiftCopy:
	and	$0F
	cp	3
	jr	nc,PCT_RotateRight
	; copy previous phase to new one for right shifted gfx in 3 parts
PCT_ShiftCopyDest:
	ld	de,KKU_PHASES_ADDR + KKU_GFX_SIZE_BYTE
							; selfmod.code: destination mem.addr of copy
	or	a
	jr	nz,PCT_SkipStoreLookupAddr
PCT_PhAddrLookup:
	ld	hl,KKU_PHASES_ADDR_LOOKUP+2
	ld	(hl),e				; store current shifted phase start address
	inc	hl
	ld	(hl),d
	inc	hl
	ld	(PCT_PhAddrLookup+1),hl
	ld	bc,KKU_GFX_SIZE1		; copy previous shifted text gfx in 3 parts
	jr	PCT_ShiftCopyJoin
PCT_SkipStoreLookupAddr:
	ld	bc,KKU_GFX_SIZE2		; copy previous shifted text gfx in 3 parts
	dec	a
	jr	z,PCT_ShiftCopyJoin
	ld	bc,KKU_GFX_SIZE3		; copy previous shifted text gfx in 3 parts

PCT_ShiftCopyJoin:
PCT_ShiftCopyOrig:
	ld	hl,KKU_PHASES_ADDR		; selfmod.code: source mem.addr of copy
	ldir
	ld	(PCT_ShiftCopyOrig+1),hl
	ld	(PCT_ShiftCopyDest+1),de
	ld	(PCT_RR_MemAddr+1),hl
	ret

PCT_RotateRight:
	; Rotate right 1 phase in 13 parts
PCT_RR_MemAddr:
	ld	hl,$1313
	ld	bc,(3*KKU_GFX_WIDTH_BYTE)+$100 ; 3 lines rotate 6 times
	cp	9
	jr	c,PCT_RR_7_Lines
	ld	bc,(2*KKU_GFX_WIDTH_BYTE)+$100 ; 2 lines rotate 7 times (6*3+7*2=32)
PCT_RR_7_Lines:
	or	a					; CF=false
PCT_RotateRightLoop:
	rr	(hl)					; shift right with 1 bit (1px)
	inc	hl
	dec	c
	jr	nz,PCT_RotateRightLoop
	djnz	PCT_RotateRightLoop

	ld	(PCT_RR_MemAddr+1),hl
	ret

;-------------------------------------------------------------------------------
MLTCOL_WIDTH_BYTE		EQU	11		; width of multicolor area in bytes
MLTCOL_HEIGHT_PX		EQU	192		; height of multicolor area in px
MLTCOL_TOPLEFT_ADDR		EQU	$5800	; mem.addr of multicolor area top left
MLTCOL_LD_DE_OPCODE		EQU	$11		; op.code of LD DE,nnnn instruction
MLTCOL_LDI_OPCODE1		EQU	$ED		; 1st op.code of LDI instruction
MLTCOL_LDI_OPCODE2		EQU	$A0		; 2nd op.code of LDI instruction
MLTCOL_LD_A_OPCODE		EQU	$3E		; op.code of LD A,n
MLTCOL_OUT_OPCODE		EQU	$D3		; code of op.code of OUT (n),A
MLTCOL_DEC_BC_OPCODE	EQU	$0B		; code of op.code of DEC BC
MLTCOL_NOP_OPCODE		EQU	$00		; code of op.code of NOP
MLTCOL_RET_OPCODE		EQU	$C9		; op.code of RET instruction

; Generate multicolor unrolled code.
; Generated code is:
;	ld de,attribute address
;	ldi 11 times
;	repeat the above 192 times
; in:  -
; out: -
; mod: AF,BC,DE,HL
GEN_MLTCOL_CODE:
GMC_GenCodeAddr:
	ld	hl,MLTCOL_CODE_PROC
GMC_AttrAddr:
	ld	de,MLTCOL_TOPLEFT_ADDR	; 1st attribute line mem.addr.
	ld	c,MLTCOL_HEIGHT_PX/6	; ...for each pixel line
							; separate it 6 runs to fit in 28000T
GMC_LineLoop:
	ld	(hl),MLTCOL_LD_DE_OPCODE	; LD DE,nnnn
	inc	hl
	ld	(hl),e
	inc	hl
	ld	(hl),d
	inc	hl
	ld	b,MLTCOL_WIDTH_BYTE
GMC_LdiLoop:
GMC_FirstLineCycle:
	ld	a,MLTCOL_HEIGHT_PX/6
	cp	c
	jr	nz,GMC_Not1stLine
	ld	a,MLTCOL_WIDTH_BYTE-6
	cp	b
	jr	nz,GMC_Not1stLine
	ld	(hl),MLTCOL_LD_A_OPCODE	; LD A,n
	inc	hl
	ld	a,(COLOR_BORDER_MID)
	ld	(hl),a
	inc	hl
	ld	(hl),MLTCOL_OUT_OPCODE	; OUT ($FE),A
	inc	hl
	ld	(hl),$FE
	inc	hl
	ld	(hl),MLTCOL_DEC_BC_OPCODE ; DEC BC - just for correct timing
	inc	hl
	ld	(hl),MLTCOL_NOP_OPCODE	; NOP
	inc	hl
	ld	(hl),MLTCOL_NOP_OPCODE	; NOP
	inc	hl
	dec	b					; skip 2 LDIs (1 DEC B + 1 DJNZ)
	jr	GMC_NextAttr
GMC_Not1stLine:
	ld	(hl),MLTCOL_LDI_OPCODE1	; LDI * 11 (or *9 in the 1st line)
	inc	hl
	ld	(hl),MLTCOL_LDI_OPCODE2
	inc	hl
GMC_NextAttr:
	djnz	GMC_LdiLoop

; --- if lower 16k is not contended memory, 9 additional loop will do the timing
;	ld	b,9
; GMC_NopLoop:
;	ld	(hl),0
;	inc	hl
;	djnz	GMC_NopLoop
;---------------------

	ld	a,c
	and	$7
	dec	a
	jr	nz,GMC_SameAttrRow
	ld	a,$20
	add	a,e
	ld	e,a
	ld	a,d
	adc	a,0
	ld	d,a
GMC_SameAttrRow:
	dec	c
	jr	nz,GMC_LineLoop
	ld	(hl),MLTCOL_RET_OPCODE	; ret-will be overwr if not in the last run
	
	ld	(GMC_GenCodeAddr+1),hl	; save addresses for next run
	ld	(GMC_AttrAddr+1),de
	ld	a,$FF
	ld	(GMC_FirstLineCycle+1),a
	ret

;-------------------------------------------------------------------------------
COPY_MLTCOL_ATTR:
MLTCOL_ATTR_LOADED_ADDR:
	ld	hl,$1313
CMCA_Dest:
	ld	de,MLTCOL_LINES_ATTR_ADDR
	ld	bc,MLTCOL_WIDTH_BYTE*MLTCOL_HEIGHT_PX/2
							; only copies half of it in one run
	ldir
	ld	(CMCA_Dest+1),de
	ld	(MLTCOL_ATTR_LOADED_ADDR+1),hl
	ret
