;;----------------------------------------------------------------------
;; This example shows how to use SCR SW ROLL to software scroll
;; a rectangular region of the screen up and down by 1 char line (8 scanlines).
;;
;; 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_sw_roll equ &bc50
txt_set_cursor equ &bb75
txt_output equ &bb5a
mc_wait_flyback equ &bd19
scr_ink_encode equ &bc2c
scrl_rect_left equ 5			;; left coord
scrl_rect_right equ 31			;; right coord
scrl_rect_top equ 5				;; top coord
scrl_rect_bottom equ 15			;; bottom coord
scrl_width equ scrl_rect_right-scrl_rect_left+1
scrl_height equ scrl_rect_bottom-scrl_rect_top+1
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

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

;; initialise background, so we can see that just a rectangular area is scrolled.
ld h,1
ld l,1
call txt_set_cursor

ld bc,scr_height*scr_width
init_back:
ld a,'-'
call txt_output
dec bc
ld a,b
or c
jr nz,init_back

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

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

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

;; initialise scroll area
;; 
;; fill with chars
ld h,scrl_rect_left
ld l,scrl_rect_top
ld c,scrl_width
ld b,scrl_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

;;----------------------------------------------------------------------
;; 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

;;----------------------------------------------------------------------
;; 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
ld h,scrl_rect_left-1				;; left
ld d,scrl_rect_right-1			;; right
ld l,scrl_rect_top-1				;; top
ld e,scrl_rect_bottom-1			;; bottom
call scr_sw_roll

call set_scrl_char_coord

call get_scrl_char

ld b,scrl_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,scrl_rect_left
ld l,scrl_rect_top
call txt_set_cursor
ret

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

set_scrl_char_coord_u:
ld h,scrl_rect_left
ld l,scrl_rect_bottom
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