/* Kitsune's Curse Copyright (C) 2020-2023 Juan J. Martinez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "splib.h" #include "font.h" //#define SPRITE_DEBUG //#define FENCE_DEBUG struct st_tile tiles[TMW * TMH]; struct st_tile *dirty; uint8_t *mini_buffer; // faster struct st_tile *tile_p; #ifdef FENCE_DEBUG // (sprite th * 2 + 2) * msx sprites #define MAX_MINI_BUFFER (3 * 2 + 2) * 10 uint8_t mini_buffer_cnt; #endif void pad_numbers(uint8_t *s, uint8_t limit, uint16_t number) { s += limit; *s = 0; do { limit--; *--s = (number % 10) + '0'; number /= 10; } while (limit); } #pragma save #pragma disable_warning 85 void set_hw_border(uint8_t c) __z88dk_fastcall { // *INDENT-OFF* __asm; ld bc, #0x7f10 out (c), c ld c, l out (c), c __endasm; // *INDENT-ON* } #pragma restore #pragma save #pragma disable_warning 85 void set_hw_ink(uint8_t ink, uint8_t c) { // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld a, (hl) inc hl ld e, (hl) ld bc, #0x7f00 out (c), a ld a, #0x40 or e out (c), a __endasm; // *INDENT-ON* } #pragma restore void wait_vsync() { // *INDENT-OFF* __asm; ld b, #0xf5 keep_waiting: in a, (c) rra jr nc, keep_waiting __endasm; // *INDENT-ON* } void clear_screen() { memset((uint8_t*)0xc000, 0, 16383); } // this is quite slow, use it only where speed is not an issue uint16_t screen_addr(uint16_t x, uint16_t y) { // up to 160 x 200 return (0xc000 + x + ((y / 8) * 80) + ((y % 8) * 2048)); } void init_tiles() { uint8_t i, j; memset(tiles, 0, sizeof(struct st_tile) * TMW * TMH); for (j = 0; j < TMH; ++j) for (i = 0; i < TMW; ++i) tiles[i + j * TMW].saddr = screen_addr((uint16_t)i * TW / 2, 32 + (uint16_t)j * TH); dirty = NULL; mini_buffer = (uint8_t *)BUFF_ADDR; #ifdef FENCE_DEBUG mini_buffer_cnt = 0; #endif } void update_screen() { // tiles are expected to be 8x8 pixels // *INDENT-OFF* __asm; call _wait_int6 ld hl, (_dirty) update_loop: ld a, h or l jr z, update_done ; baddr in de; and reset it xor a ld e, (hl) ld (hl), a inc hl ld d, (hl) ld (hl), a inc hl ; clean dirty flag res 7, d ld a, d or e jr nz, linked_buffer ; not linked, use the original tile ; hl has *t ld e, (hl) inc hl ld d, (hl) dec hl linked_buffer: ; skip *t inc hl inc hl ; saddr in a, c ld c, (hl) inc hl ld a, (hl) inc hl ; pointing to next push hl ; baddr in hl ex de, hl ; saddr to de ld e, c ld d, a ld a, #8 put_tile0: ldi ldi ldi ldi dec a jp z, put_tile2 ; inc destination ex de, hl ld bc, #0x07fc add hl, bc jp nc, put_tile1 ld bc, #0xc048 add hl, bc put_tile1: ex de, hl jr put_tile0 put_tile2: ; next dirty tile pop hl ld a, (hl) inc hl ld h, (hl) ld l, a jp update_loop update_done: ; a is 0 ld (_dirty), a ld (_dirty + #1), a #ifdef FENCE_DEBUG ld (_mini_buffer_cnt), a #endif ; reset mini buffers (begin buffer at 0x0100) ld (_mini_buffer), a inc a ld (_mini_buffer + #1), a __endasm; // *INDENT-ON* } void validate_screen() { for (; dirty; dirty = dirty->n) dirty->baddr = 0; // dirty is NULL mini_buffer = (uint8_t *)BUFF_ADDR; } void invalidate_screen() { uint16_t i; dirty = NULL; mini_buffer = (uint8_t *)BUFF_ADDR; for (i = TMW * TMH; i; i--) { tiles[i - 1].baddr &= ADDR_BITS; invalidate_tile(&tiles[i - 1]); } } void invalidate_tile(struct st_tile *st) __z88dk_fastcall { /* if (st->baddr & DIRTY_BIT) return; st->baddr |= DIRTY_BIT; st->n = dirty; dirty = st; */ // *INDENT-OFF* __asm; ld e, l ld d, h ; test for dirty bit inc hl ld a, (hl) bit #7, a ret nz ; set dirty bit set #7, a ld (hl), a ; set *n to dirty ld a, #5 add a, l ld l, a adc a, h sub l ld h, a ld a, (#_dirty) ld (hl), a inc hl ld a, (#_dirty + #1) ld (hl), a ; set dirty to *st ld (_dirty), de __endasm; // *INDENT-ON* } struct st_tile *get_tile_xy(uint8_t x, uint8_t y) { // x and y in tilemap coordinates #ifdef FENCE_DEBUG if (x > TMW || y > TMH) set_hw_border(0x4b); #endif return &tiles[x + (uint16_t)y * TMW]; } #pragma save #pragma disable_warning 59 uint8_t is_invalid_tile(struct st_tile *st) __z88dk_fastcall { // *INDENT-OFF* __asm; inc hl ld a, (hl) and #128 ld l, a __endasm; // *INDENT-ON* } #pragma restore #pragma save #pragma disable_warning 59 uint8_t is_invalid_tile2(struct st_tile *st) __z88dk_fastcall { // *INDENT-OFF* __asm; inc hl ld a, (hl) and #128 jr nz, is_invalid ld bc, #(TMW * 8) add hl, bc ld a, (hl) and #128 is_invalid: ld l, a __endasm; // *INDENT-ON* } #pragma restore void erase_tile(struct st_tile *st) __z88dk_fastcall { // *INDENT-OFF* __asm; ; if it has a linked buffer, it was erased already ; testing MSB only inc hl ld a, (hl) or a ret nz dec hl ; and if there is no linked buffer, it is not invalidated ; set dirty bit (if not set already) jp _invalidate_tile __endasm; // *INDENT-ON* } void link_buffer(struct st_tile *st) __z88dk_fastcall { // *INDENT-OFF* __asm; ; check is not linked already ; testing MSB only inc hl ld a, (hl) and #127 ret nz dec hl #ifdef FENCE_DEBUG ld a, (_mini_buffer_cnt) inc a ld (_mini_buffer_cnt), a cp #MAX_MINI_BUFFER jp c, mini_buffers_ok ld hl, #0x58 jp _set_hw_border mini_buffers_ok: #endif ; save *st push hl ; allocate a new buffer ex de, hl ld hl, (_mini_buffer) ld c, l ld b, h ex de, hl ; new buffer to baddr, preserve dirty bit ld (hl), c inc hl ld a, (hl) and #128 or b ld (hl), a dec hl ; move mini buffer pointer ex de, hl ld hl, #(TW * TH / 2) add hl, bc ld (_mini_buffer), hl ex de, hl ; baddr to de ld e, c ld d, b ; *t to hl inc hl inc hl ld a, (hl) inc hl ld h, (hl) ld l, a #ifdef SPRITE_DEBUG ld hl, #_bgtiles + 14 * 32 #endif ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ldi ; *st pop hl jp _invalidate_tile __endasm; // *INDENT-ON* } void put_tile(const uint8_t *t, struct st_tile *st) { st->t = t; invalidate_tile(st); } #pragma save #pragma disable_warning 85 void erase_sprite(uint8_t x, uint8_t y, uint8_t th) { // for 8 pixels wide sprites, th in tiles // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld c, (hl) ; x inc hl ld e, (hl) ; y inc hl ld b, (hl) ; th ld a, e ; out of bounds check cp #(TMH * TH - 8) jr nc, no_inc_th and #0x07 jr z, no_inc_th inc b no_inc_th: ld l, c ; x srl l srl l srl l ld a, e ; y srl a srl a srl a add a, b ; add th ld h, a push bc push hl call _get_tile_xy pop af pop bc ; hl has the tile addr .db 0xdd ld l, b ld a, c and #0x07 jr z, erase_tile_loop_no_extra_x erase_tile_loop: xor a ld de, #(TMW * 8) sbc hl, de ; dec tile ptr 1 row as th decrements push hl call _erase_tile pop hl push hl ld de, #8 add hl, de ; tile ptr + 1 call _erase_tile pop hl .db 0xdd dec l jr nz, erase_tile_loop ret erase_tile_loop_no_extra_x: xor a ld de, #(TMW * 8) sbc hl, de ; dec tile ptr 1 row as th decrements push hl call _erase_tile pop hl .db 0xdd dec l jr nz, erase_tile_loop_no_extra_x __endasm; // *INDENT-ON* } #pragma restore const uint8_t inv_table[] = { 0, 2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, 32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, 16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, 48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63, 128, 130, 129, 131, 136, 138, 137, 139, 132, 134, 133, 135, 140, 142, 141, 143, 160, 162, 161, 163, 168, 170, 169, 171, 164, 166, 165, 167, 172, 174, 173, 175, 144, 146, 145, 147, 152, 154, 153, 155, 148, 150, 149, 151, 156, 158, 157, 159, 176, 178, 177, 179, 184, 186, 185, 187, 180, 182, 181, 183, 188, 190, 189, 191, 64, 66, 65, 67, 72, 74, 73, 75, 68, 70, 69, 71, 76, 78, 77, 79, 96, 98, 97, 99, 104, 106, 105, 107, 100, 102, 101, 103, 108, 110, 109, 111, 80, 82, 81, 83, 88, 90, 89, 91, 84, 86, 85, 87, 92, 94, 93, 95, 112, 114, 113, 115, 120, 122, 121, 123, 116, 118, 117, 119, 124, 126, 125, 127, 192, 194, 193, 195, 200, 202, 201, 203, 196, 198, 197, 199, 204, 206, 205, 207, 224, 226, 225, 227, 232, 234, 233, 235, 228, 230, 229, 231, 236, 238, 237, 239, 208, 210, 209, 211, 216, 218, 217, 219, 212, 214, 213, 215, 220, 222, 221, 223, 240, 242, 241, 243, 248, 250, 249, 251, 244, 246, 245, 247, 252, 254, 253, 255 }; #pragma save #pragma disable_warning 85 void put_sprite_rc_nm(uint8_t *d, uint8_t dox, uint8_t doy, uint8_t w, uint8_t h, const uint8_t *s, uint8_t sox, uint8_t soy) { // x offset must be even /* uint8_t i, j; d += dox + doy * TW / 2; s += sox + soy * TW / 2; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) *d++ = *s++; s += (TW / 2) - w; d += (TW / 2) - w; } */ // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld e, (hl) inc hl ld d, (hl) inc hl ; de has *d ld b, #0 ld c, (hl) ; bc has dox inc hl ld a, (hl) sla a sla a ex de, hl ; add dox add hl, bc ld c, a ; bc has doy * TW / 2 add hl, bc ex de, hl ; d* is ready push de inc hl inc hl inc hl ld e, (hl) inc hl ld d, (hl) inc hl ; de has *s ; b is 0 ld c, (hl) ; bc has sox inc hl ld a, (hl) sla a sla a ; a has soy * TW / 2 ex de, hl ; add sox add hl, bc ld c, a ; add soy * TW / 2 add hl, bc ex de, hl ld hl, #(6 + 2) add hl, sp ld c, (hl) inc hl ; c is w ; the reminder ld a, #4 sub c ld (no_inv_sub_w_nm + 1), a ; and build jump addr sla a ld (no_inv_inner_w_nm + 1), a ld a, (hl) ; h ; hl has *s ex de, hl ; *d pop de ld b, #0 no_inv_height_nm: no_inv_inner_w_nm: jr no_inv_inner_w_nm ldi ldi ldi ldi ; b is 0 ; inc *d no_inv_sub_w_nm: ld c, #0 ex de, hl add hl, bc ex de, hl ; inc *s add hl, bc dec a jr nz, no_inv_height_nm __endasm; // *INDENT-ON* } #pragma restore #pragma save #pragma disable_warning 85 void put_sprite_rc(uint8_t *d, uint8_t dox, uint8_t doy, uint8_t w, uint8_t h, const uint8_t *s, uint8_t sox, uint8_t soy, uint8_t inv) { /* uint8_t i, j; d += dox + doy * TW / 2; if (inv) s += TW - 2 * (1 + sox) + soy * TW; else s += 2 * sox + soy * TW; if (inv) { for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { *d &= inv_table[*s++]; *d++ |= inv_table[*s]; s -= 3; } s += (TW / 2 + w) * 2; d += TW / 2 - w; } } else { for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { *d &= *s++; *d++ |= *s++; } s += (TW / 2 - w) * 2; d += TW / 2 - w; } } */ // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld e, (hl) inc hl ld d, (hl) inc hl ; de has *d ld b, #0 ld c, (hl) ; bc has dox inc hl ld a, (hl) sla a sla a ex de, hl add hl, bc ld c, a ; bc has doy * TW / 2 add hl, bc ex de, hl ; d* is ready push de inc hl inc hl inc hl ld e, (hl) inc hl ld d, (hl) inc hl ; de has *s ; b is 0 inc hl ld c, (hl) sla c sla c sla c ; bc has soy ex de, hl add hl, bc ex de, hl ; common *s part is ready inc hl ld a, (hl) or a jr z, setup_no_inv ; blit inv ld hl, #(10 + 2) add hl, sp ; b is 0 ld c, (hl) inc c sla c xor a sub a, c ld c, a ld a, #0 sbc b ld b, a ; bc has - 2 - 2 x sox ex de, hl add hl, bc ld bc, #8 ; add TW add hl, bc ex de, hl ; de has *s ready for inv ld hl, #(6 + 2) add hl, sp ld a, (hl) ; w ; set this in the code ld (inv_inner_w + 1), a ld b, a ld a, #4 sub b ld (inv_sub_w + 1), a ld a, #4 add b sla a ld (inv_add_w + 1), a inc hl ld a, (hl) ; *d pop hl ex de, hl push ix .db 0xdd ld h, a ; h inv_height: .db 0xdd inv_inner_w: ld l, #0 inv_width: ; add 8-bit number to a 16-bit reg ; ; add a, l ; ld l, a ; adc a, h ; sub l ; ld h, a ; first flip bg ld a, (de) ld bc, #_inv_table add a, c ld c, a adc a, b sub c ld b, a ld a, (bc) ; and mask; or sprite and (hl) inc hl or (hl) ; flip again ld bc, #_inv_table add a, c ld c, a adc a, b sub c ld b, a ld a, (bc) ld (de), a inc de dec hl dec hl dec hl .db 0xdd dec l jr nz, inv_width ; inc *s inv_add_w: ld a, #0 add a, l ld l, a adc a, h sub l ld h, a ; inc *d inv_sub_w: ld a, #0 add a, e ld e, a adc a, d sub e ld d, a .db 0xdd dec h jr nz, inv_height pop ix ret setup_no_inv: ld hl, #(10 + 2) add hl, sp ; b is 0 ld c, (hl) sla c ex de, hl add hl, bc ; add 2 x sox to *s ex de, hl ld hl, #(6 + 2) add hl, sp ld a, (hl) inc hl ; w ld (no_inv_inner_w + 1), a ld b, a ld a, #4 sub b ld (no_inv_sub_w + 1), a sla a ld (no_inv_sub_w2 + 1), a ld c, (hl) ; h ; hl has *s ex de, hl ; *d pop de no_inv_height: no_inv_inner_w: ld b, #0 no_inv_width: ; and mask; or sprite ld a, (de) and (hl) inc hl or (hl) inc hl ld (de), a inc de djnz no_inv_width ; inc *d no_inv_sub_w: ld a, #0 add a, e ld e, a adc a, d sub e ld d, a ; inc *s (x2) no_inv_sub_w2: ld a, #0 add a, l ld l, a adc a, h sub l ld h, a dec c jr nz, no_inv_height __endasm; // *INDENT-ON* } #pragma restore void put_sprite4(const uint8_t *s, uint8_t x, uint8_t y, uint8_t th, uint8_t inv) { /* uint8_t xoffs, yoffs; xoffs = (x % TW) / 2; yoffs = y % TH; tile_p = get_tile_xy(x >> 3, (y >> 3)); // top link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, yoffs, TW / 2 - xoffs, TH - yoffs, s, 0, 0, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, yoffs, xoffs, TH - yoffs, s, TW / 2 - xoffs, 0, inv); } if (th > 1) { // center 1 tile_p = get_tile_xy(x >> 3, (y >> 3) + 1); link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, 0, TW / 2 - xoffs, TH, s, 0, TH - yoffs, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, 0, xoffs, TH, s, TW / 2 - xoffs, TH - yoffs, inv); } if (th > 2) { // center 2 tile_p = get_tile_xy(x >> 3, (y >> 3) + 2); link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, 0, TW / 2 - xoffs, TH, s, 0, 2 * TH - yoffs, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, 0, xoffs, TH, s, TW / 2 - xoffs, 2 * TH - yoffs, inv); } // reminder if (yoffs) { tile_p = get_tile_xy(x >> 3, (y >> 3) + 3); link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, 0, TW / 2 - xoffs, yoffs, s, 0, 3 * TH - yoffs, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, 0, xoffs, yoffs, s, TW / 2 - xoffs, 3 * TH - yoffs, inv); } } } else { // reminder if (yoffs) { tile_p = get_tile_xy(x >> 3, (y >> 3) + 2); link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, 0, TW / 2 - xoffs, yoffs, s, 0, 2 * TH - yoffs, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, 0, xoffs, yoffs, s, TW / 2 - xoffs, 2 * TH - yoffs, inv); } } } } else { // reminder if (yoffs) { tile_p = get_tile_xy(x >> 3, (y >> 3) + 1); link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), xoffs, 0, TW / 2 - xoffs, yoffs, s, 0, TH - yoffs, inv); if (xoffs) { tile_p++; link_buffer(tile_p); put_sprite_rc((uint8_t *)(tile_p->baddr & ADDR_BITS), 0, 0, xoffs, yoffs, s, TW / 2 - xoffs, TH - yoffs, inv); } } } */ // *INDENT-OFF* __asm; ; for xoffs and yoffs push af ld ix, #0 add ix, sp ld a, 2 + 4 (ix) and #7 srl a ld 0 (ix), a ; (x mod 8) / 2 -> xoffs ld a, 3 + 4 (ix) and #7 ld 1 (ix), a ; (y mod 8) -> yoffs ld e, 2 + 4 (ix) srl e srl e srl e ld d, 3 + 4 (ix) srl d srl d srl d push de ; x >> 3, y >> 3 call _get_tile_xy pop af ; *tile push hl ; fastcall, does not use ix call _link_buffer pop hl push hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS ld b, 5 + 4 (ix) ; inv ld c, #0 push bc ; soy ld b, #0 push bc inc sp ; soy ld c, 0 + 4 (ix) ld b, 1 + 4 (ix) push bc ; *s ; xoffs & yoffs are on the stack ld a, #4 sub 0 (ix) ld c, a ld a, #8 sub 1 (ix) ld b, a push bc ; TH / 2 - xoffs, TH - yoffs ld c, 0 (ix) ld b, 1 (ix) push bc ; xoffs, yoffs push de ; baddr call _put_sprite_rc ld iy, #0 add iy, sp ld a, 0 (ix) or a jr z, put_sprite4_xaligned0 ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #8 add hl, bc ; *tile + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs call _put_sprite_rc put_sprite4_xaligned0: ld a, 4 + 4 (ix) cp #1 jp z, put_sprite4_reminder_th1 ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * 20) add hl, bc ; *tile + TMW push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters ld a, 0 (ix) ld 2 (iy), a ; xoffs xor a ld 3 (iy), a ld 8 (iy), a ; 0 ld a, #4 sub 0 (ix) ld 4 (iy), a ; TW / 2 - xoffs ld a, #8 ld 5 (iy), a ; TH ; a is 8 sub 1 (ix) ld 9 (iy), a ; TH - yoffs call _put_sprite_rc ld a, 0 (ix) or a jr z, put_sprite4_xaligned1 ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * (20 + 1)) add hl, bc ; *tile + TMW + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs call _put_sprite_rc put_sprite4_xaligned1: ld a, 4 + 4 (ix) cp #2 jp z, put_sprite4_reminder_th2 ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * 20 * 2) add hl, bc ; *tile + TMW * 2 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters ld a, 0 (ix) ld 2 (iy), a ; xoffs xor a ld 3 (iy), a ld 8 (iy), a ; 0 ld a, #4 sub 0 (ix) ld 4 (iy), a ; TW / 2 - xoffs ld a, #8 ld 5 (iy), a ; TH sla a ; TH * 2 sub 1 (ix) ld 9 (iy), a ; 2 * TH - yoffs call _put_sprite_rc ld a, 0 (ix) or a jr z, put_sprite4_reminder ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * (20 * 2 + 1)) add hl, bc ; *tile + 2 * TMW + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs call _put_sprite_rc put_sprite4_reminder: ld a, 1 (ix) or a ; yoffs jp z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * 20 * 3) add hl, bc ; *tile + TMW * 3 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters ld a, 0 (ix) ld 2 (iy), a ; xoffs xor a ld 3 (iy), a ld 8 (iy), a ; 0 ld a, #4 sub 0 (ix) ld 4 (iy), a ; TW / 2 - xoffs ld a, 1 (ix) ld 5 (iy), a ; yoffs ld a, #(8 * 3) sub 1 (ix) ld 9 (iy), a ; 3 * TH - yoffs call _put_sprite_rc ld a, 0 (ix) or a jp z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * (20 * 3 + 1)) add hl, bc ; *tile + 3 * TMW + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs ld a, #(8 * 3) sub 1 (ix) ld 9 (iy), a ; 3 * TH - yoffs call _put_sprite_rc jr put_sprite4_done put_sprite4_reminder_th2: ld a, 1 (ix) or a ; yoffs jr z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * 20 * 2) add hl, bc ; *tile + TMW * 2 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters ld a, 0 (ix) ld 2 (iy), a ; xoffs xor a ld 3 (iy), a ld 8 (iy), a ; 0 ld a, #4 sub 0 (ix) ld 4 (iy), a ; TW / 2 - xoffs ld a, 1 (ix) ld 5 (iy), a ; yoffs ld a, #(8 * 2) sub 1 (ix) ld 9 (iy), a ; 2 * TH - yoffs call _put_sprite_rc ld a, 0 (ix) or a jr z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * (20 * 2 + 1)) add hl, bc ; *tile + 2 * TMW + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs ld a, #(8 * 2) sub 1 (ix) ld 9 (iy), a ; 2 * TH - yoffs call _put_sprite_rc put_sprite4_done: ld hl, #15 add hl, sp ld sp, hl ret put_sprite4_reminder_th1: ld a, 1 (ix) or a ; yoffs jr z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * 20 * 1) add hl, bc ; *tile + TMW * 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters ld a, 0 (ix) ld 2 (iy), a ; xoffs xor a ld 3 (iy), a ld 8 (iy), a ; 0 ld a, #4 sub 0 (ix) ld 4 (iy), a ; TW / 2 - xoffs ld a, 1 (ix) ld 5 (iy), a ; yoffs ld a, #8 sub 1 (ix) ld 9 (iy), a ; TH - yoffs call _put_sprite_rc ld a, 0 (ix) or a jr z, put_sprite4_done ; *tile ld l, 11 (iy) ld h, 12 (iy) ld bc, #(8 * (20 * 1 + 1)) add hl, bc ; *tile + 1 * TMW + 1 push hl ; fastcall, does not use ix or iy call _link_buffer pop hl ld e, (hl) inc hl ld d, (hl) res #7, d ; de has baddr & ADDR_BITS pop af push de ; save parameter ; update parameters that changed xor a ld 2 (iy), a ; 0 ld c, 4 (iy) ; TW / 2 - xoffs ld a, 0 (ix) ld 4 (iy), a ; xoffs ld 8 (iy), c ; TW / 2 - xoffs ld a, #8 sub 1 (ix) ld 9 (iy), a ; TH - yoffs call _put_sprite_rc jp put_sprite4_done __endasm; // *INDENT-ON* } uint8_t tink, fink, bink; uint8_t tfont[16]; void _set_text_ink(uint8_t c, uint8_t *t) { *t = ((c & 1) << 7) | ((c & 1) << 6) | ((c & 4) << 3) | ((c & 4) << 2) | ((c & 2) << 2) | ((c & 2) << 1) | ((c & 8) >> 2) | ((c & 8) >> 3); } void set_text_ink(uint8_t c, uint8_t c2, uint8_t c3) { _set_text_ink(c, &tink); _set_text_ink(c2, &fink); _set_text_ink(c3, &bink); } #include void cpc_PutSp(char *sprite, char height, char width, int address); void tint_text() { // *INDENT-OFF* __asm; ld de, #_tfont ld hl, #_tink ld c, (hl) ld hl, #_fink ld a, (hl) ld hl, #_bink ld h, (hl) ld l, a ld b, #6 tint_loop1: ld a, (de) and c ld (de), a inc de djnz tint_loop1 ld b, #6 tint_loop2: ld a, (de) and l ld (de), a inc de djnz tint_loop2 ld b, #4 tint_loop3: ld a, (de) and h ld (de), a inc de djnz tint_loop3 __endasm; // *INDENT-ON* } #pragma save #pragma disable_warning 85 void put_text(const char *s, uint8_t x, uint8_t y) { /* while(*s) { memcpy(tfont, spfont[*s - 31], 16); tint_text(); cpc_PutSp(tfont, 8, 2, screen_addr(x, y)); x += 2; s++; } */ // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld e, (hl) inc hl ld d, (hl) ; s inc hl ld b, (hl) ; x inc hl ld c, (hl) ; y put_text_loop: push de push bc ld hl, #16 push hl ld a, (de) sub #31 ld l, a ; h is 0 add hl, hl add hl, hl add hl, hl add hl, hl ld bc, #_spfont add hl, bc push hl ld hl, #_tfont push hl call _memcpy pop af pop af pop af call _tint_text pop hl push hl ld a, h ld h, #0 push hl ld l, a push hl call _screen_addr pop af pop af push hl ld hl, #0x0208 push hl ld hl, #_tfont push hl call _cpc_PutSp pop af pop af pop af pop bc pop de inc b inc b inc de ld a, (de) or #0 jr nz, put_text_loop __endasm; // *INDENT-ON* } #pragma restore #pragma save #pragma disable_warning 85 void fill_screen(const uint8_t *t) __z88dk_fastcall { // *INDENT-OFF* __asm; ex de, hl ld hl, #_tiles ld bc, #(TMW * TMH) fill_screen_loop: inc hl inc hl ld (hl), e inc hl ld (hl), d inc hl inc hl inc hl inc hl inc hl dec bc ld a, c or b jr nz, fill_screen_loop jp _invalidate_screen __endasm; // *INDENT-ON* } #pragma restore uint8_t abs_sub(uint8_t a, uint8_t b) { /* if (a > b) return (a - b); else return (b - a); */ // *INDENT-OFF* __asm; ld hl, #2 add hl, sp ld b, (hl) inc hl ld c, (hl) ld a, b sub c jr c, b_minus_a ld l, a ret b_minus_a: ld a, c sub b ld l, a __endasm; // *INDENT-ON* } // EOF