diff --git a/presets/c64/scrolling2.c b/presets/c64/scrolling2.c new file mode 100644 index 00000000..0c9cf0b4 --- /dev/null +++ b/presets/c64/scrolling2.c @@ -0,0 +1,281 @@ + +#include + +#include "scrolling.h" + +#define VICBANK 0x8000 +#define BUFFER_A (byte*) 0x8000 +#define BUFFER_B (byte*) 0x8400 + +sbyte scroll_fine_x; +sbyte scroll_fine_y; +byte origin_x; +byte origin_y; +byte* hidbuf; +byte* visbuf; +byte colorbuf[COLS*ROWS]; +int pixofs_x; +int pixofs_y; +sbyte fine_correct_x; +sbyte fine_correct_y; + +byte scroll_dir; +byte scroll_seq; + +// + +static void wait_offscreen(void) { + while (VIC.rasterline < 250 && VIC.rasterline > 40) ; +} + +void scroll_swap(void) { + byte* tmp; + // swap hidden and visible buffers + tmp = hidbuf; + hidbuf = visbuf; + visbuf = tmp; + // set VIC bank address + wait_offscreen(); + VIC.addr = (VIC.addr & 0xf) | (((word)visbuf >> 8) << 2); +} + +void copy_color_ram_slow() { + memcpy(COLOR_RAM, colorbuf, COLS*ROWS); +} + +void copy_color_ram_fast() { + // fast copy loop for upper 1/2 of color ram + asm("ldy #0"); + asm("@loop:"); + asm("lda %v,y", colorbuf); + asm("sta $d800,y"); + asm("lda %v + $100,y", colorbuf); + asm("sta $d900,y"); + asm("iny"); + asm("bne @loop"); + // second loop for lower 1/2 of color ram + asm("@loop2:"); + asm("lda %v + $200,y", colorbuf); + asm("sta $da00,y"); + asm("lda %v + $300,y", colorbuf); + asm("sta $db00,y"); + asm("@skip: iny"); + asm("bne @loop2"); +} + +void copy_to_hidden_buffer_slow() { + memcpy(hidbuf, visbuf, COLS*ROWS); +} + +void copy_to_hidden_buffer_fast() { + // self-modifying code + asm("ldy %v+1", visbuf); + asm("sty @loop+2+6*0"); + asm("iny"); + asm("sty @loop+2+6*1"); + asm("iny"); + asm("sty @loop+2+6*2"); + asm("iny"); + asm("sty @skip-1-3"); + asm("ldy %v+1", hidbuf); + asm("sty @loop+5+6*0"); + asm("iny"); + asm("sty @loop+5+6*1"); + asm("iny"); + asm("sty @loop+5+6*2"); + asm("iny"); + asm("sty @skip-1"); + // fast copy loop + asm("ldy #0"); + asm("@loop:"); + asm("lda $8000,y"); + asm("sta $8000,y"); + asm("lda $8100,y"); + asm("sta $8100,y"); + asm("lda $8200,y"); + asm("sta $8200,y"); + asm("cpy #$e8"); + asm("bcs @skip"); + asm("lda $8300,y"); + asm("sta $8300,y"); + asm("@skip: iny"); + asm("bne @loop"); +} + +void scroll_start(byte dir) { + if (scroll_seq == 0 && dir) { + scroll_dir = dir; + scroll_seq = 8; + // correct sprites b/c our fine offset is one pixel + // off depending on last scroll direction + if (dir & SCROLL_LEFT) fine_correct_x = 1; + else if (dir & SCROLL_RIGHT) fine_correct_x = 0; + if (dir & SCROLL_UP) fine_correct_y = 1; + else if (dir & SCROLL_DOWN) fine_correct_y = 0; + } +} + +void scroll_step_move_buffer(char* src, char* dst) { + word size = COLS*ROWS; + if (scroll_dir & SCROLL_LEFT) { + ++src; + --size; + } + if (scroll_dir & SCROLL_RIGHT) { + ++dst; + --size; + } + if (scroll_dir & SCROLL_UP) { + src += COLS; + size -= COLS; + } + if (scroll_dir & SCROLL_DOWN) { + dst += COLS; + size -= COLS; + } + memmove(dst, src, size); +} + +void scroll_step_draw_cells() { + if (scroll_dir & SCROLL_UP) ++origin_y; + if (scroll_dir & SCROLL_DOWN) --origin_y; + if (scroll_dir & SCROLL_LEFT) { + ++origin_x; + scroll_draw_column(COLS-1); + } + if (scroll_dir & SCROLL_RIGHT) { + --origin_x; + scroll_draw_column(0); + } + if (scroll_dir & SCROLL_UP) { + scroll_draw_row(ROWS-1); + } + if (scroll_dir & SCROLL_DOWN) { + scroll_draw_row(0); + } +} + +void scroll_step_move_sprites() { + // copy sprites from visible to hidden buffer + memcpy(hidbuf + 0x3f8, visbuf + 0x3f8, 8); +} + +void scroll_update_pixofs() { + // fine scroll starts at 8-5 = 32107 or 12-8 = 45670 + if (scroll_dir & SCROLL_LEFT) { + pixofs_x -= 1; + scroll_fine_x = (scroll_seq - 5) & 7; + } + if (scroll_dir & SCROLL_RIGHT) { + pixofs_x += 1; + scroll_fine_x = (12 - scroll_seq) & 7; + } + if (scroll_dir & SCROLL_UP) { + pixofs_y -= 1; + scroll_fine_y = (scroll_seq - 5) & 7; + } + if (scroll_dir & SCROLL_DOWN) { + pixofs_y += 1; + scroll_fine_y = (12 - scroll_seq) & 7; + } +} + +void scroll_offset_sprites(byte delta) { + byte dx = 0; + byte dy = 0; + // fine scroll starts at 8-5 = 32107 or 12-8 = 45670 + if (scroll_dir & SCROLL_LEFT) { + dx = -delta; + } + if (scroll_dir & SCROLL_RIGHT) { + dx = delta; + } + if (scroll_dir & SCROLL_UP) { + dy = -delta; + } + if (scroll_dir & SCROLL_DOWN) { + dy = delta; + } + VIC.spr_pos[0].x += dx; + VIC.spr_pos[1].x += dx; + VIC.spr_pos[0].y += dy; + VIC.spr_pos[1].y += dy; +} + +void scroll_update_scroll_regs() { + wait_offscreen(); + VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | scroll_fine_y; + VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | scroll_fine_x; +} + +void scroll_next_step(void) { + switch (--scroll_seq) { + case 7: + scroll_step_move_buffer(visbuf, hidbuf); + break; + case 6: + scroll_step_move_buffer(colorbuf, colorbuf); + break; + case 5: + scroll_step_draw_cells(); + break; + case 4: + scroll_step_move_sprites(); + break; + case 3: + scroll_swap(); + copy_color_ram_fast(); + break; + } +} + +void scroll_update(void) { + if (scroll_seq) { + scroll_update_pixofs(); + scroll_update_scroll_regs(); + scroll_offset_sprites(1); + scroll_next_step(); + } +} + +void scroll_finish(void) { + while (scroll_seq) { + scroll_update_pixofs(); + if (scroll_seq == 4) { scroll_offset_sprites(8); } + scroll_next_step(); + } +} + +void scroll_setup(void) { + origin_x = origin_y = 0; + pixofs_x = pixofs_y = 0; + scroll_fine_x = scroll_fine_y = 3; + scroll_dir = 0; + scroll_seq = 0; + + // setup screen buffer addresses + hidbuf = BUFFER_A; + visbuf = BUFFER_B; + + memset(BUFFER_A, 0, 0x800); + memset(colorbuf, 0, sizeof(colorbuf)); + + SET_VIC_BANK(VICBANK); + + // set up 24 line / 38 column mode to hide edges + VIC.ctrl1 &= ~0x08; // 24 lines + VIC.ctrl2 &= ~0x08; // 38 columns +} + +void scroll_refresh(void) { + byte i; + for (i=0; i<25; i++) { + scroll_draw_row(i); + } + scroll_swap(); + copy_color_ram_fast(); + copy_to_hidden_buffer_fast(); + scroll_dir = 0; + scroll_seq = 0; + scroll_fine_x = scroll_fine_y = 3; +}