Code: Select all
DEBUG equ 0
DEBUG_LOOP equ 0
;; 0x300 bytes (768)
;; might be at a 256-byte boundary (slightly faster)
TILEMAP equ 0xf000
;; 0x900 bytes (2304)
;; must be at a 256-byte boundary
UDGADDR equ 0xf300
;; top/bottom skip: [0..7]
TILE_SKIP_TOP equ 2
TILE_SKIP_BOTTOM equ 2
;; left/right skip: any sane value, need to have at least one tile visible
TILE_SKIP_LEFT equ 2
TILE_SKIP_RIGHT equ 2
TILE_ROW_SKIP equ TILE_SKIP_LEFT+TILE_SKIP_RIGHT
TILEMAP_LAST_VIS_TILE equ TILEMAP+32*24-1-TILE_SKIP_RIGHT-32*TILE_SKIP_BOTTOM
org 32768
IF DEBUG
di ;; for debug
ELSE
;; for basic
exx
push hl
ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; to make things easier, i'm unrolling normal UDG here
;; normal UDG is 8 bitmap bytes and attribute
;; you can skip this unrolling, and use prepared data instead
call prepare_udg_set
again:
IF !DEBUG && DEBUG_LOOP
halt
ld a,1
out (#fe),a
ENDIF
;; call main blitting routine
call blit_tilemap
IF DEBUG
jr $
ENDIF
IF !DEBUG && DEBUG_LOOP
xor a
out (#fe),a
jp again
ENDIF
IF !DEBUG
;; for basic
pop hl
exx
ENDIF
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; in:
;; none
;;
;; out:
;; BC,DE,HL,AF: dead
;; B'C', D'E', H'L': dead
;;
;; doesn't use IX/IY, or stack tricks
;;
;; tile #0 is "attribute print" (i.e. only attrs will be printed)
;;
blit_tilemap:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; draw attributes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ld bc,TILEMAP_LAST_VIS_TILE
ld de,0x5800+32*24-1-TILE_SKIP_RIGHT-32*TILE_SKIP_BOTTOM
ld hl,UDGADDR+256*8
exx
;; alternate set: counters
ld c,24-TILE_SKIP_TOP-TILE_SKIP_BOTTOM ; height
print_one_row_loop:
;; alternate set: counters
ld b,32-TILE_ROW_SKIP ; width
print_one_tile:
;; here we should be at "counters"
exx
ld a,(bc)
ld l,a
ldd
inc hl ; restore high byte (required for zero tile)
exx
djnz print_one_tile
; next row
dec c
jp z,attr_done
;; alternate set: counters
exx
;; normal set: addresses
; skip invisible tiles
DUP TILE_ROW_SKIP
dec bc
dec de
EDUP
exx
jp print_one_row_loop
attr_done:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; draw bitmap
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; top 1/3
ld bc,TILEMAP+TILE_SKIP_LEFT+32*TILE_SKIP_TOP
ld hl,0x4000+TILE_SKIP_LEFT+32*TILE_SKIP_TOP
exx
ld c,8-TILE_SKIP_TOP ; row count
call do_one_row
;; alternate set (counters)
;; middle 1/3
ld bc,TILEMAP+TILE_SKIP_LEFT+32*8
ld hl,0x4800+TILE_SKIP_LEFT
exx
;; alternate set (counters)
ld c,8 ; row count
call do_one_row
;; alternate set (counters)
;; bottom 1/3
ld bc,TILEMAP+TILE_SKIP_LEFT+32*8*2
ld hl,0x5000+TILE_SKIP_LEFT
exx
;; alternate set (counters)
ld c,8-TILE_SKIP_BOTTOM ; row count
call do_one_row
;; alternate set (counters)
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; in:
;; C': height
;; BC: tilemap
;; HL: scraddr
;; registers must be at the alternate set (counters)
;;
;; out:
;; DE,HL,AF: dead
;; BC: right after last read tilemap byte
;; B'C': dead
;; registers are at the alternate set (counters)
;;
do_one_row:
ld b,32-TILE_ROW_SKIP
;; do it tile by tile
do_one_tile:
;; alternate set (counters)
exx
;; normal set (addresses)
ld a,(bc)
IF TILEMAP&0xff
inc bc
ELSE
inc c
ENDIF
or a
jp z,skip_one_tile
ld (do_one_tile_save_addr+1),hl
ld (one_tile_udg_addr+1),a
one_tile_udg_addr:
ld de,UDGADDR
; tile bitmap
DUP 7
ld a,(de)
ld (hl),a
inc d
inc h
EDUP
; avoid two useless increments
ld a,(de)
ld (hl),a
do_one_tile_save_addr:
ld hl,0 ; self-modifying code, fixed above
skip_one_tile:
inc l
exx
djnz do_one_tile
dec c
ret z
; we are done with the row
;; alternate set (counters)
exx
;; normal set (addresses)
IF TILE_ROW_SKIP > 3 && (TILEMAP&0xff) == 0
ld a,TILE_ROW_SKIP
add a,c
ld c,a
ELSE
DUP TILE_ROW_SKIP
IF TILEMAP&0xff
inc bc
ELSE
inc c
ENDIF
EDUP
ENDIF
IF TILE_ROW_SKIP > 3
ld a,TILE_ROW_SKIP
add a,l
ld l,a
ELSE
DUP TILE_ROW_SKIP
inc l
EDUP
ENDIF
exx
jp do_one_row
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; unroll linear UDG set to `UDGADDR`
;;
prepare_udg_set:
ld c,UDG_COUNT
ld hl,UDG_SET
ld de,UDGADDR
; char by char
prepare_next_char:
push de
ld b,9
prepare_char_loop:
ld a,(hl)
ld (de),a
inc hl
inc d
djnz prepare_char_loop
pop de
inc e
dec c
jr nz,prepare_next_char
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; linear UDG set
;;
UDG_COUNT equ 8
UDG_SET:
;; bitmap, then attribute
defb 00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b, 00000000b
defb 00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b, 01011011b
defb 11001100b,01100110b,00110011b,10011001b,11001100b,01100110b,00110011b,10011001b, 01110000b
defb 00111100b,01111110b,11111111b,11111111b,11111111b,11111111b,01111110b,00111100b, 01000011b
defb 00000000b,00000011b,00001111b,00011111b,00111111b,00111111b,01111111b,01111111b, 01000011b
defb 00000000b,11000000b,11110000b,11111000b,11111100b,11111100b,11111110b,11111110b, 01000011b
defb 01111111b,01111111b,00111111b,00111111b,00011111b,00001111b,00000011b,00000000b, 01000011b
defb 11111110b,11111110b,11111100b,11111100b,11111000b,11110000b,11000000b,00000000b, 01000011b
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; tilemap
;;
org TILEMAP
defb 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
defb 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
defb 2,2,2,2,0,2,0,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
defb 2,2,2,0,0,2,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 4,5,0,0,0,1,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,3,4,5,4,5,0, 1,0,3,4,5,1,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,1,1,1,1,7,3, 1,3,1,6,5,1,5,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,1,6,7,6,7,0, 1,0,1,6,7,1,1,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,6,7,0,0,0,0,6, 7,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2
defb 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
defb 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
defb 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; unrolled UDG set
;; contains first bytes for all 256 tiles, then next bytes, and so on
org UDGADDR