1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-29 14:51:17 +00:00
8bitworkshop/presets/c64/scrolling2.c
2023-02-07 14:16:38 -05:00

282 lines
5.8 KiB
C

#include <string.h>
#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;
}