;;----------------------------------------------------------------------
;; This example shows how to use SCR HW ROLL to hardare scroll
;; a rectangular region of the screen up and down by 1 char line (8 scanlines).
;;
;; The effect is not good because drawing takes a long time.
;;
;; NOTES:

;; Scrolling down:
;; 1. When the area is scrolled down the top-most line will now be 1 char line down.
;; 2. The line will be cleared to the encoded ink we define.
;; 3. We then draw only the top-most line to make the scroll continue.
;; 
;; Scrolling up:
;; 1. When the area is scrolled up the bottom-most line will now be 1 char line up.
;; 2. The line will be cleared to the encoded ink we define.
;; 3. We then draw only the bottom-most line to make the scroll continue.
;;
;; For both we remember what char we want to draw at top and bottom, and each time
;; we scroll we update this.
;; 
;; The char could also be thought of as the Y coordinate within a tilemap, and we can
;; then draw all the tiles on that row.
;;
;; Use cursor keys to control.
;;----------------------------------------------------------------------

scr_set_mode equ &bc0e
scr_hw_roll equ &bc4d
txt_set_cursor equ &bb75
txt_output equ &bb5a
mc_wait_flyback equ &bd19
scr_ink_encode equ &bc2c
scr_width equ 40				;; width of screen in chars
scr_height equ 25				;; height of screen in chars
km_test_key equ &bb1e

;;----------------------------------------------------------------------

org &4000
nolist

;;----------------------------------------------------------------------


;; set mode
ld a,1
call scr_set_mode

;;----------------------------------------------------------------------

;; we clear to ink 2, get encoded version
ld a,2
call scr_ink_encode
ld (clear_encoded_ink),a

;;----------------------------------------------------------------------

;; calc initial char at top and bottom for when we update scroll
ld a,'A'
ld (char_top),a
ld b,scr_height-1
calc_char_bottom:
call upd_scrl_char_u
djnz calc_char_bottom
ld (char_bottom),a

;;----------------------------------------------------------------------

call init_scrl

;;----------------------------------------------------------------------
;; the main loop

main_loop:
call mc_wait_flyback


;; check keys
call do_keys

ld a,(update_scroll)
or a
call nz,draw_scroll
		
jp main_loop

;;----------------------------------------------------------------------

init_scrl:
;; initialise scroll area
;; 
;; fill with chars
ld h,1
ld l,1
ld c,scr_width
ld b,scr_height
ld a,(char_top)			;; char for first line
init_scrl_h:
push af
push bc
push hl
push af
;; set char coordinate for start of line
call txt_set_cursor
pop af

init_scrl_w:
;; display char and move to right
call txt_output
dec c
jr nz,init_scrl_w
pop hl
pop bc
pop af
inc l			;; go down next char line
call upd_scrl_char_u
djnz init_scrl_h
ret


;;----------------------------------------------------------------------
;; depending on scroll direction we choose to draw at the top or the bottom
;; of the area to maintain the scroll
draw_scroll:
ld a,(update_scroll)
or a
jp z,main_loop
xor a
ld (update_scroll),a

;;----------------------------------------------------------------------

;; based on scrolling direction, update the char 
;; that will be drawn at top and bottom

call upd_char_scrl

ld a,(direction)
ld b,a
							;; direction 
								;; 0=down, <>0 up
ld a,(clear_encoded_ink)		;; clear colour
call scr_hw_roll


call set_scrl_char_coord

call get_scrl_char

ld b,scr_width
draw_new_line:
call txt_output
djnz draw_new_line	

ret

;;----------------------------------------------------------------------


;;-----------------------------------------------------------------------------------------------------
;; check keyboard
;;
;; cursor keys

do_keys:
ld a,0*8+0
call km_test_key
jr nz,move_up
ld a,0*8+2
call km_test_key
jr nz,move_down
ret

;;----------------------------------------------------------------------
;; handle scrolling up
;; 
move_up:
ld a,&ff
ld (direction),a
ld a,1
ld (update_scroll),a
ret

;;----------------------------------------------------------------------
;; handle scrolling down

move_down:
ld a,0
ld (direction),a
ld a,1
ld (update_scroll),a
ret

;;----------------------------------------------------------------------
;; based on scrolling direction determine where to draw chars
set_scrl_char_coord:
ld a,(direction)
or a
jp z,set_scrl_char_coord_d
jp set_scrl_char_coord_u

;;----------------------------------------------------------------------

set_scrl_char_coord_d:
ld h,1
ld l,1
call txt_set_cursor
ret

;;----------------------------------------------------------------------

set_scrl_char_coord_u:
ld h,1
ld l,scr_height
call txt_set_cursor
ret

;;----------------------------------------------------------------------
;; based on drawing direction get char to draw to continue scroll

get_scrl_char:
ld a,(direction)
or a 
ld a,(char_top)
ret z
ld a,(char_bottom)
ret

;;----------------------------------------------------------------------

upd_char_scrl:
ld a,(direction)
or a
jp z,upd_char_scrl_d
jp upd_char_scrl_u
;;----------------------------------------------------------------------

upd_char_scrl_d:
ld a,(char_top)
call upd_scrl_char_d
ld (char_top),a

ld a,(char_bottom)
call upd_scrl_char_d
ld (char_bottom),a
ret
;;----------------------------------------------------------------------

upd_char_scrl_u:
ld a,(char_top)
call upd_scrl_char_u
ld (char_top),a

ld a,(char_bottom)
call upd_scrl_char_u
ld (char_bottom),a
ret

;;----------------------------------------------------------------------

;; top is initially A,
;; when we scroll down A will be shifted to 2nd line
;; then the new line should show Z

;; wrap around Z->A
upd_scrl_char_d:
dec a
cp 'A'-1
ret nz
ld a,'Z'
ret
;;----------------------------------------------------------------------


;; top is initially A,
;; when we scroll down A will be shifted to 2nd line
;; then the new line should show Z
upd_scrl_char_u:
inc a
cp 'Z'+1
ret nz
ld a,'A'
ret
;;----------------------------------------------------------------------

;; 0 for down, !=0 for up
direction:
defb 0
;;----------------------------------------------------------------------

char_top:
defb 0
char_bottom:
defb 0
;;----------------------------------------------------------------------
;; 0 to do not update scroll, !=0 for doing scroll
update_scroll:
defb 0
;;----------------------------------------------------------------------
;; encoded ink for clearing line
clear_encoded_ink:
defb 0