From 472b9f952d4fe376b5d8417cee5483e1abe3dff6 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Thu, 11 Aug 2022 15:27:20 -0500 Subject: [PATCH] c64: presets, new vsync --- presets/c64/bcd.c | 21 +- presets/c64/bcd.h | 6 +- presets/c64/climber.c | 8 +- presets/c64/common.c | 12 +- presets/c64/common.h | 65 ++- presets/c64/fullscrollgame.c | 616 +++++++++++++++++++++++ presets/c64/hello.dasm | 41 -- presets/c64/joygame.c | 131 +++++ presets/c64/joymove.c | 45 +- presets/c64/mandel.c | 20 +- presets/c64/{multilines.c => mcbitmap.c} | 54 +- presets/c64/mcbitmap.h | 15 + presets/c64/multisprite.ca65 | 203 ++++++++ presets/c64/musicplayer.c | 4 +- presets/c64/rasterirq.ca65 | 6 +- presets/c64/rasterirq.h | 8 +- presets/c64/scroll1.c | 77 ++- presets/c64/scroll2.c | 76 +-- presets/c64/scroll3.c | 47 +- presets/c64/scroll4.c | 7 +- presets/c64/scroll5.c | 5 +- presets/c64/scrolling.c | 22 +- presets/c64/scrolling.h | 2 + presets/c64/siddemo.c | 77 ++- presets/c64/side_scroller.c | 341 +++++++++++++ presets/c64/sidmacros.h | 55 ++ presets/c64/sidplaysfx.ca65 | 1 + presets/c64/skeleton.cc65 | 3 + presets/c64/sprite_collision.c | 55 +- presets/c64/sprite_test.c | 42 -- presets/c64/sprites.c | 9 +- presets/c64/sprites.h | 25 +- presets/c64/spritesinborder.c | 17 +- presets/c64/test_multiplex.c | 136 +++++ presets/c64/testmultispritelib.c | 149 ++++++ src/common/baseplatform.ts | 24 +- src/machine/c64.ts | 8 +- src/machine/cpc.ts | 4 +- src/machine/vic20.ts | 4 +- src/platform/c64.ts | 35 +- test/cli/testworker.js | 1 + 41 files changed, 2122 insertions(+), 355 deletions(-) create mode 100644 presets/c64/fullscrollgame.c delete mode 100644 presets/c64/hello.dasm create mode 100644 presets/c64/joygame.c rename presets/c64/{multilines.c => mcbitmap.c} (70%) create mode 100644 presets/c64/mcbitmap.h create mode 100644 presets/c64/multisprite.ca65 create mode 100644 presets/c64/side_scroller.c create mode 100644 presets/c64/sidmacros.h delete mode 100644 presets/c64/sprite_test.c create mode 100644 presets/c64/test_multiplex.c create mode 100644 presets/c64/testmultispritelib.c diff --git a/presets/c64/bcd.c b/presets/c64/bcd.c index 6f56db5e..9020d2c8 100644 --- a/presets/c64/bcd.c +++ b/presets/c64/bcd.c @@ -2,12 +2,19 @@ #include "common.h" word bcd_add(word a, word b) { - register word c, d; // intermediate values - c = a + 0x0666; // add 6 to each BCD digit - d = c ^ b; // sum without carry propagation - c += b; // provisional sum - d = ~(c ^ d) & 0x1110; // just the BCD carry bits - d = (d >> 2) | (d >> 3); // correction - return c - d; // corrected BCD sum + asm("sed"); + a += b; + asm("cld"); + return a; +} + +void draw_bcd_word(word address, word bcd) { + byte i; + address += 4; + for (i=0; i<4; i++) { + POKE(address, (bcd & 0b1111) + '0'); + address--; + bcd >>= 4; + } } diff --git a/presets/c64/bcd.h b/presets/c64/bcd.h index b8daf0d0..5dc1b336 100644 --- a/presets/c64/bcd.h +++ b/presets/c64/bcd.h @@ -1,3 +1,7 @@ +/* add two BCD numbers */ unsigned int bcd_add(unsigned int a, unsigned int b); -unsigned int bcd_add2(unsigned int a, unsigned int b); + +/* print a 16-bit BCD to a specific address */ +void draw_bcd_word(word address, word bcd_value); + diff --git a/presets/c64/climber.c b/presets/c64/climber.c index b33d70ff..27f0d37b 100644 --- a/presets/c64/climber.c +++ b/presets/c64/climber.c @@ -69,7 +69,7 @@ const byte ITEM_CHARS[3][4] = { #define NUM_SPRITE_PATTERNS 13 /*{w:12,h:21,bpp:2,brev:1,count:13,aspect:2}*/ -const char SPRITE_DATA[NUM_SPRITE_PATTERNS][3*21] = { +const char SPRITE_DATA[NUM_SPRITE_PATTERNS][64] = { // left direction { 0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xEA,0x00, @@ -765,15 +765,11 @@ void game_displaylist(void) { // main program void main() { - byte i; - // set up scrolling scroll_setup(); // set up sprites sprite_clear(); - for (i=0; i #include -typedef uint8_t byte; -typedef uint16_t word; -typedef int8_t sbyte; -typedef enum { false, true } bool; +typedef uint8_t byte; // 8-bit unsigned +typedef int8_t sbyte; // 8-bit signed +typedef uint16_t word; // 16-bit unsigned +typedef enum { false, true } bool; // boolean -#define COLS 40 -#define ROWS 25 +#define COLS 40 // total # of columns +#define ROWS 25 // total # of rows + +///// MACROS ///// + +// lookup screen address macro +#define SCRNADR(base,col,row) ((base)+(col)+(row)*40) + +// default screen base address on startup #define DEFAULT_SCREEN ((void*)0x400) +// wait until next frame, same as waitvsync() #define wait_vblank waitvsync +// is raster line > 255? +#define RASTER_HIBIT (VIC.ctrl1 & 0x80) +// set VIC Bank (given the start address) +#define SET_VIC_BANK(_addr) \ + CIA2.pra = (CIA2.pra & ~3) | (((((_addr)>>8)&0xc0)>>6)^3); + +// set VIC character memory (given the start address) +#define SET_VIC_CHAR(_addr) \ + VIC.addr = (VIC.addr & 0b11110001) | ((((_addr)>>8)&0x38)>>2); + +// set VIC screen memory (given the start address) +#define SET_VIC_SCREEN(_addr) \ + VIC.addr = (VIC.addr & 0b00001111) | ((((_addr)>>8)&0x3c)<<2); + +// set scrolling registers +#define SET_SCROLL_Y(_y) \ + VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | (_y); + +#define SET_SCROLL_X(_x) \ + VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | (_x); + + +// enable RAM from 0xa000-0xffff, disable interrupts +#define ENABLE_HIMEM() \ + asm("php"); \ + asm("sei"); \ + POKE(1, PEEK(1) & ~0b111); + +// enable ROM and interrupts +#define DISABLE_HIMEM() \ + POKE(1, PEEK(1) | 0b111); \ + asm("plp"); + +///// FUNCTIONS ///// + +// wait until specific raster line void raster_wait(byte line); -char* get_vic_bank_start(void); +// get current VIC bank start address +char* get_vic_bank_start(); + +// get current screen memory address +char* get_screen_memory(); + +// return key in buffer, or 0 if none (BIOS call) +char __fastcall__ poll_keyboard(); #endif diff --git a/presets/c64/fullscrollgame.c b/presets/c64/fullscrollgame.c new file mode 100644 index 00000000..2088c508 --- /dev/null +++ b/presets/c64/fullscrollgame.c @@ -0,0 +1,616 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +//#resource "c64-sid.cfg" +#define CFGFILE c64-sid.cfg + +#include "common.h" +//#link "common.c" + +#include "scrolling.h" +//#link "scrolling2.c" + +#include "sprites.h" +//#link "sprites.c" + +//#link "level2.ca65" + +#define CAMERA_OFFSET_X 158 +#define CAMERA_OFFSET_Y 120 +#define CAMERA_MAX_DX 12 +#define CAMERA_MAX_DY 8 + +#define MAX_ACTORS 8 +#define ACTOR_OFFSET_X 28 +#define ACTOR_OFFSET_Y 30 +#define ACTOR_WIDTH 24 +#define ACTOR_HEIGHT 21 + +#define JUMP_VELOCITY -36 +#define MAX_FALL_VELOCITY 64 +#define MAX_HORIZ_VELOCITY 16 + +#define MAP_COLS 16 +#define MAP_ROWS 16 + +#define DEFAULT_CHAR chartileset_data[16] +#define DEFAULT_COLOR chartileset_colour_data[1] + +#define FLAG_SOLID 1 +#define FLAG_PLATFORM 2 +#define FLAG_LADDER 4 + + + +static byte framecount; +static byte framemask; + +const byte BITMASKS[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +extern const byte charset_data[]; +extern const byte charset_attrib_data[]; +extern const byte chartileset_data[]; +extern const byte chartileset_colour_data[]; +extern const byte chartileset_tag_data[]; +extern const byte* map_row_pointers[]; + +static byte tileflagmap[MAP_ROWS*MAP_COLS]; + +static byte tileindex; +static byte tilechar; + +static bool get_cell_at(byte world_x, byte world_y) { + sbyte col = world_x >> 2; + sbyte row = world_y >> 2; + byte xofs = world_x & 3; + byte yofs = world_y & 3; + if (col < 0 || col >= MAP_COLS || row < 0 || row >= MAP_ROWS) { + return false; + } else { + tileindex = map_row_pointers[row][col]; + tilechar = chartileset_data[xofs + yofs*4 + tileindex*16]; + return true; + } +} + +byte compute_tile_flags() { + switch (tileindex) { + case 3: return FLAG_PLATFORM; + case 4: return FLAG_PLATFORM; + case 5: return FLAG_SOLID; + case 6: return FLAG_LADDER; + case 7: return FLAG_PLATFORM | FLAG_LADDER; + case 8: return FLAG_SOLID; + default: return 0; + } +} + +byte get_tile_flags(word world_x, word world_y) { + byte tilex = world_x >> 5; + byte tiley = world_y >> 5; + if (tilex < MAP_COLS && tiley < MAP_ROWS) + return tileflagmap[tilex + tiley*MAP_COLS]; + else + return 0; +} + +static void build_tile_flag_map(void) { + byte x,y; + byte i=0; + for (y=0; yxx; + word ypos = actor->yy; + byte shape = 240; + switch (actor->state) { + case STANDING: + if (actor->xvel && actor->xx & 4) shape += 4; + if (!actor->faceleft) shape += 5; + break; + case JUMPING: + shape += 2; + if (!actor->faceleft) shape += 5; + break; + case CLIMBING: + shape += 1; + if (actor->yy & 2) shape += 5; + break; + } + sprite_draw(0, + xpos + pixofs_x + fine_correct_x + ACTOR_OFFSET_X, + ypos + pixofs_y + fine_correct_y + ACTOR_OFFSET_Y, + shape); +} + +const char velocity_bitmasks[8] = { + 0b00000000, // 0/8 + 0b00001000, // 1/8 + 0b00100010, // 2/8 + 0b10010010, // 3/8 + 0b01010101, // 4/8 + 0b01110101, // 5/8 + 0b11101110, // 6/8 + 0b11110111, // 7/8 +// 0b11111111, // 8/8 +}; + +static byte box[4]; // hit box + +/* +void actor_set_position(register Actor* actor, + word world_x, + word world_y, + ActorState state) { + actor->xx = world_x; + actor->yy = world_y; + actor->state = state; + actor->tileindex = (world_x>>5) | (world_y>>5)*MAP_COLS; +} +*/ + +void move_actor(register Actor* actor, + sbyte cmd_dx, + sbyte cmd_dy) { + word xx,yy; + byte flags; + sbyte dx = cmd_dx; + sbyte dy = cmd_dy; + bool state = actor->state; + + xx = actor->xx + dx; + yy = actor->yy + dy; + // if we are standing, move hit box 1 pixel below our feet + if (state == STANDING) { + yy += 1 - dy; // cancel out any climbing vertical offset (dy) + dy = 0; + } + // get hit box flags on all 4 corners + { + box[0] = get_tile_flags(xx, yy-ACTOR_HEIGHT); + box[1] = get_tile_flags(xx+ACTOR_WIDTH, yy-ACTOR_HEIGHT); + box[2] = get_tile_flags(xx, yy); + box[3] = get_tile_flags(xx+ACTOR_WIDTH, yy); + // cancel x velocity if either top corners is solid + if (dx < 0 && ((box[0] | box[2]) & FLAG_SOLID)) { + if (state != STANDING || box[0] & FLAG_SOLID) { + actor->xvel = 0; + dx = 0; + } + } + else if (dx > 0 && ((box[1] | box[3]) & FLAG_SOLID)) { + if (state != STANDING || box[1] & FLAG_SOLID) { + actor->xvel = 0; + dx = 0; + } + } + // cancel upward velocity if both top corners are solid + if (dy < 0 && ((box[0] | box[1]) & FLAG_SOLID)) { + actor->yvel = 0; + dy = 0; + } + switch (state) { + case JUMPING: + // are we moving downward? + if (dy > 0) { + // hit a solid brick? + flags = box[2] | box[3]; + if (flags & FLAG_SOLID) { + // don't land if we are bumping against a wall + // but land if entire bottom border is solid + if (box[2] & box[3] & FLAG_SOLID) flags = FLAG_PLATFORM; + else if (box[0] & box[2] & FLAG_SOLID) { } + else if (box[1] & box[3] & FLAG_SOLID) { } + else flags = FLAG_PLATFORM; + } + // land on platform, but only if we + // transit past the lower boundary of a cell + if (flags & FLAG_PLATFORM) { + // maximum speed is 8 pixels/frame + if ((yy & 31) <= 8) { + if ((actor->yy & 31) >= 24) { + actor->yy |= 31; + actor->yvel = 0; + dy = 0; + actor->state = STANDING; + } + } + } + } + break; + case STANDING: + // if either bottom corner is empty, fall down + if ((box[2] | box[3]) == 0) { + actor->state = JUMPING; + } + // climbing a ladder? + else if (cmd_dy) { + // look at top corners if going up, bottom corners if down + flags = cmd_dy < 0 ? box[0] & box[1] : box[2] & box[3]; + if (flags & FLAG_LADDER) { + actor->state = CLIMBING; + } else { + dy = 0; + } + } + break; + case CLIMBING: + // any flags set on bottom corners? + flags = box[2] & box[3]; + if (!(flags & FLAG_LADDER)) { + // top of ladder, stand up + if (dy < 0) { + actor->state = STANDING; + } else { + // bottom of ladder, don't go thru floor + actor->state = JUMPING; + dy = 0; + } + } + break; + } + } + // update position and tile coordinate + // unless we zeroed out the velocity + if (dx) actor->xx += dx; + if (dy) actor->yy += dy; +} + +void control_actor(register Actor* actor, byte joy) { + sbyte dx = 0; + sbyte dy = 0; + sbyte speed = 1; + ActorState state = actor->state; + // jump button + if (JOY_BTN_1(joy) && state == STANDING) { + actor->yvel = JUMP_VELOCITY; + actor->state = state = JUMPING; + framecount = 0; // TODO? + } + // update position based on x/y velocity + if (actor->xvel) { + dx += actor->xvel >> 3; + if (framemask & velocity_bitmasks[actor->xvel & 7]) { + dx++; + } + } + if (actor->yvel) { + dy += actor->yvel >> 3; + if (framemask & velocity_bitmasks[actor->yvel & 7]) { + dy++; + } + } + // apply gravity when jumping or falling + if (state == JUMPING && + actor->yvel < MAX_FALL_VELOCITY) { + actor->yvel += 2; + } + // arrow keys give left/right velocity + if (JOY_LEFT(joy)) { + actor->faceleft = true; + if (actor->xvel > -MAX_HORIZ_VELOCITY) + actor->xvel -= speed; + } else if (JOY_RIGHT(joy)) { + actor->faceleft = false; + if (actor->xvel < MAX_HORIZ_VELOCITY) + actor->xvel += speed; + } else { + // slow down actor to a stop, horizontally + if (actor->xvel) actor->xvel /= 2; + } + // climb ladder? + if (state == STANDING || state == CLIMBING) { + if (JOY_UP(joy)) { dy = -1; } + if (JOY_DOWN(joy)) { dy = 1; } + } + // move sprite + if (dx | dy) { + move_actor(actor, dx, dy); + } +} + +void camera_follow(register Actor* actor) { + int dx, dy; + byte moving = actor->xvel || actor->yvel; + // compute distance between player and camera + dx = CAMERA_OFFSET_X - pixofs_x - actor->xx; + dy = CAMERA_OFFSET_Y - pixofs_y - actor->yy; + // if we are moving, scroll only when distance + // from center is greater + if (moving) { + if (dx < -CAMERA_MAX_DX) dx += CAMERA_MAX_DX; + else if (dx > CAMERA_MAX_DX) dx -= CAMERA_MAX_DX; + else dx = 0; + if (dy < -CAMERA_MAX_DY) dy += CAMERA_MAX_DY; + else if (dy > CAMERA_MAX_DY) dy -= CAMERA_MAX_DY; + else dy = 0; + } + // divide dx and dy by 16 + dx >>= 4; + dy >>= 4; + // do we need to scroll? + if (dx || dy) { + // what direction? + byte dir = 0; + if (dx < 0) dir |= SCROLL_LEFT; + if (dx > 0) dir |= SCROLL_RIGHT; + if (dy < 0) dir |= SCROLL_UP; + if (dy > 0) dir |= SCROLL_DOWN; + // start the scroll (ignored if one is already going) + scroll_start(dir); + // fast 8-pixel scroll if screen is moving too fast + if (moving && (abs(dx) >= 4 || abs(dy) >= 4)) { + scroll_finish(); + } + } +} + +void setup_sprites(void) { + sprite_clear(); + sprite_set_shapes(SPRITE_DATA, 240, NUM_SPRITE_PATTERNS); + sprshad.spr_color[0] = COLOR_WHITE; + sprshad.spr_mcolor = 0xff; + VIC.spr_mcolor0 = 12; + VIC.spr_mcolor1 = 14; +} + +void setup_charset() { + // multicolor character mode + VIC.ctrl2 |= 0x10; + VIC.bgcolor0 = 6; + VIC.bgcolor1 = 0; + VIC.bgcolor2 = 1; + + // select character set @ 0x8800 + VIC.addr = 0x12; + memcpy((char*)0x8800, charset_data, 0x800); +} + +void next_frame() { + char joy; + // increment frame counter + framemask = BITMASKS[++framecount & 7]; + // get joystick bits + joy = joy_read(0); + // move player + control_actor(player, joy); + // move the camera if needed + camera_follow(player); + // animate sprite in shadow sprite ram + draw_actor(player); + // wait for vblank + wait_vblank(); + // then update sprite registers + sprite_update(visbuf); + // do scrolling stuff each frame + scroll_update(); +} + +void main(void) { + + clrscr(); + + // setup scrolling library + scroll_setup(); + + // setup the character set for the level + setup_charset(); + + // copy sprites to VIC bank + setup_sprites(); + + // build cache for actor-level collisions + build_tile_flag_map(); + + // install the joystick driver + joy_install (joy_static_stddrv); + + // repaint screen memory w/ the map + scroll_refresh(); + + player->xx = 3*32+8; + player->yy = 2*32+8-16; + + player->xx = 0; + player->yy = 31; + player->state = STANDING; + /* + player->xx = 32; + player->yy = 0; + player->xx = 33; + player->yy = 100; + player->state = JUMPING; + */ +// actor_set_position(player, 63, 63, STANDING); + + // infinite loop + while (1) { + next_frame(); + } +} diff --git a/presets/c64/hello.dasm b/presets/c64/hello.dasm deleted file mode 100644 index 899940d3..00000000 --- a/presets/c64/hello.dasm +++ /dev/null @@ -1,41 +0,0 @@ - - include "cartheader.dasm" - -; program start -Temp equ $03 -Start - sei ; turn off interrupts - ldy #0 - sty $d020 ; reset border color - -Loop - lda Message,y ; load message byte - beq EOM ; 0 = end of string - clc - adc #$c0 ; + 192 - sta $400+41,y ; store to screen - iny - bne Loop ; next character -EOM -Wait1 - lda $d011 - bmi Wait1 ; wait for line < 256 -Wait2 - lda $d012 ; get current scanline -Wait3 - cmp $d012 - beq Wait3 ; wait for scanline to change - lsr - lsr - clc - adc Temp - sta $d020 ; set border color - lda $d011 ; get status bits - bpl Wait2 ; repeat until line >= 256 - sty $d020 ; reset border color - dec Temp ; scroll colors - jmp Wait1 ; endless loop -Message - ; PETSCII - http://sta.c64.org/cbm64pet.html - byte "HELLO`WORLDa" - byte 0 diff --git a/presets/c64/joygame.c b/presets/c64/joygame.c new file mode 100644 index 00000000..bb8ed422 --- /dev/null +++ b/presets/c64/joygame.c @@ -0,0 +1,131 @@ + +#include "common.h" +//#link "common.c" + +#include "sprites.h" +//#link "sprites.c" + +#define NUM_SPRITES 3 + +/*{w:12,h:21,bpp:2,brev:1,wpimg:64,count:3,aspect:2}*/ +const char SPRITE_MC_DATA[64*NUM_SPRITES] = { + 0x0A,0xAA,0x80,0x0A,0xAA,0x80,0x2A,0xAA, + 0xA0,0x2A,0xAA,0xA0,0xAA,0xAA,0xAA,0xFF, + 0xD5,0x40,0x0D,0xD7,0x40,0x3D,0xD5,0x54, + 0x37,0x55,0x54,0x37,0x55,0x54,0x35,0x55, + 0x00,0x3A,0xA0,0x00,0xEA,0xA8,0x00,0xAB, + 0xAA,0x00,0xAB,0xAA,0x00,0xAB,0xAA,0x80, + 0xAA,0xEA,0x80,0xAA,0xAA,0x80,0x0F,0xFC, + 0x00,0x0F,0xFC,0x00,0x0F,0xFF,0xC0,0x00, + + 0x02,0xAA,0xA0,0x02,0xAA,0xA0,0x0A,0xAA, + 0xA8,0x0A,0xAA,0xA8,0xAA,0xAA,0xAA,0x01, + 0x57,0xFF,0x01,0xD7,0x70,0x15,0x57,0x7C, + 0x15,0x55,0xDC,0x15,0x55,0xDC,0x00,0x55, + 0x5C,0x00,0x0A,0xAC,0x00,0x2A,0xAB,0x00, + 0xAA,0xEA,0x00,0xAA,0xEA,0x02,0xAA,0xEA, + 0x02,0xAB,0xAA,0x02,0xAA,0xAA,0x00,0x3F, + 0xF0,0x00,0x3F,0xF0,0x03,0xFF,0xF0,0x00, + + 0x00,0xAA,0x80,0x02,0xAA,0xA0,0x0A,0xAA,0xA8, + 0x0A,0xAE,0xA8,0x0A,0xBB,0xA8,0x0A,0xBA,0xA8, + 0x0A,0xBB,0xA8,0x0A,0xAE,0xA8,0x0A,0xAA,0xA8, + 0x09,0xAA,0x98,0x08,0x6A,0x48,0x08,0x1D,0x08, + 0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20, + 0x00,0x8C,0x80,0x00,0x8C,0x80,0x00,0x55,0x40, + 0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00, + 0x80, +}; + +// starting index for sprites +#define SPRITE_SHAPE 192 + +// player data +int player_x = 172; +byte player_y = 145; +byte faceleft = 0; // 0 = face right, 1 = face left + +void init_sprite_shapes(void) { + byte i; + for (i=0; i>fpshift) #define fpabs(_x) (abs(_x)) @@ -71,10 +70,11 @@ void mandelbrot (signed short x1, signed short y1, signed short x2, if (count == maxiterations) { color = (0); } else { - color = COLORS[count % MAXCOL]; + color = count < MAXCOL + ? COLORS[count] + : COLORS[MAXCOL-1]; + set_pixel(x, y, color); } - /* Set pixel */ - set_pixel(x, y, color); } } } @@ -85,11 +85,11 @@ int main (void) VIC.bgcolor0 = 0x00; /* Calc mandelbrot set */ - mandelbrot (tofp (-2), tofp (-2), tofp (2), tofp (2)); + mandelbrot (-fpone/2, -fpone, 0, -fpone/2); /* Fetch the character from the keyboard buffer and discard it */ cgetc (); - + /* Done */ return EXIT_SUCCESS; } diff --git a/presets/c64/multilines.c b/presets/c64/mcbitmap.c similarity index 70% rename from presets/c64/multilines.c rename to presets/c64/mcbitmap.c index e49d3157..b1fd72b1 100644 --- a/presets/c64/multilines.c +++ b/presets/c64/mcbitmap.c @@ -2,30 +2,34 @@ #include "common.h" //#link "common.c" +#include "mcbitmap.h" + void setup_bitmap_multi() { VIC.ctrl1 = 0x38; VIC.ctrl2 = 0x18; - // set VIC bank ($4000-$7FFF) - // https://www.c64-wiki.com/wiki/VIC_bank - CIA2.pra = 0x02; - // set VIC screen to $6000 - VIC.addr = 0x80; - // clear bitmap and screen RAM - memset((void*)0x4000, 0, 0x2000); - memset((void*)0xd800, 0, 40*25); + SET_VIC_BANK(MCB_BITMAP); + SET_VIC_CHAR(MCB_BITMAP); + SET_VIC_SCREEN(MCB_COLORS); + memset((void*)MCB_BITMAP, 0, 0x2000); + memset((void*)MCB_COLORS, 0, 0x800); + memset(COLOR_RAM, 0, 40*25); } const byte PIXMASK[4] = { ~0xc0, ~0x30, ~0x0c, ~0x03 }; const byte PIXSHIFT[4] = { 6, 4, 2, 0 }; byte is_pixel(byte x, byte y) { - word ofs = ((x>>2)*8 + (y>>3)*320) | (y&7) | 0x4000; - return PEEK(ofs) & ~PIXMASK[x & 3]; + word ofs = ((x>>2)*8 + (y>>3)*320) | (y&7) | MCB_BITMAP; + byte pixvalue; + ENABLE_HIMEM(); + pixvalue = PEEK(ofs); + DISABLE_HIMEM(); + return pixvalue & ~PIXMASK[x & 3];; } void set_pixel(byte x, byte y, byte color) { word ofs,b,cram,sram; - byte ccol,scol; + byte ccol,scol,used; byte val; if (x >= 160 || y >= 192) return; @@ -35,35 +39,44 @@ void set_pixel(byte x, byte y, byte color) { if (color == VIC.bgcolor0) { val = 0; } else { + // calculate character (and color RAM) offset cram = ((x>>2) + (y>>3)*40); - sram = cram | 0x6000; + sram = cram | MCB_COLORS; cram |= 0xd800; + // read color ram, screen memory, and used bits + ENABLE_HIMEM(); ccol = PEEK(cram); scol = PEEK(sram); - // color RAM contains unused bits (0x10 and 0x20) + used = PEEK(sram | 0x400); + DISABLE_HIMEM(); // unused in lower nibble of screen RAM? (value 2) - if (color == (scol & 0xf) || !(ccol & 0x10)) { + if (color == (scol & 0xf) || !(used & 0x10)) { val = 2; scol = (scol & 0xf0) | color; - ccol |= 0x10; + used |= 0x10; POKE(sram, scol); // unused in upper nibble of screen RAM? (value 1) - } else if (color == (scol >> 4) || !(ccol & 0x20)) { + } else if (color == (scol >> 4) || !(used & 0x20)) { val = 1; scol = (scol & 0xf) | (color << 4); - ccol |= 0x20; + used |= 0x20; POKE(sram, scol); // all other colors in use, use color RAM } else { val = 3; - ccol = 0x30 | color; + used |= 0x40; + ccol = color; + POKE(cram, ccol); } - POKE(cram, ccol); + // write to unused bit + POKE(sram | 0x400, used); } - ofs = ((x>>2)*8 + (y>>3)*320) | (y&7) | 0x4000; + ofs = ((x>>2)*8 + (y>>3)*320) | (y&7) | MCB_BITMAP; x &= 3; + ENABLE_HIMEM(); b = PEEK(ofs) & PIXMASK[x]; + DISABLE_HIMEM(); if (val) { b |= val << PIXSHIFT[x]; } @@ -86,6 +99,7 @@ void draw_line(int x0, int y0, int x1, int y1, byte color) { } } +// support recursion #pragma static-locals(push,off) byte flood_fill(byte x, byte y, byte color) { register byte x1 = x; diff --git a/presets/c64/mcbitmap.h b/presets/c64/mcbitmap.h new file mode 100644 index 00000000..0308c109 --- /dev/null +++ b/presets/c64/mcbitmap.h @@ -0,0 +1,15 @@ + +#include "common.h" + +#define MCB_COLORS 0xc000 +#define MCB_BITMAP 0xe000 + +void setup_bitmap_multi(); + +byte is_pixel(byte x, byte y); + +void set_pixel(byte x, byte y, byte color); + +void draw_line(int x0, int y0, int x1, int y1, byte color); + +byte flood_fill(byte x, byte y, byte color); diff --git a/presets/c64/multisprite.ca65 b/presets/c64/multisprite.ca65 new file mode 100644 index 00000000..47e37499 --- /dev/null +++ b/presets/c64/multisprite.ca65 @@ -0,0 +1,203 @@ + +MAX_MSPRITES = 28 + +MIN_Y_SPACING = 33 + +DEBUG = 1 + +.code + +.global _msprite_render_init +_msprite_render_init: + lda #0 + sta j + sta k + sta $d001 ; ypos #0 + sta $d003 + sta $d005 + sta $d007 + sta $d009 + sta $d00b + sta $d00d + sta $d00f ; ypos #7 + lda #$ff + sta $d015 ; sprite enable + rts + +.global _msprite_render_section +_msprite_render_section: + lda $d012 + clc + adc #MIN_Y_SPACING + sta bailout_line +@loop: +.ifdef DEBUG + inc $d020 +.endif + lda $d012 + cmp bailout_line + bcs @loopexit + ldy k + cpy #MAX_MSPRITES + bcs @loopexit + lda _msprite_order,y ; $ff = end of sprite list + tay ; Y = sprite index from sort array + lda j + asl + tax ; X = j * 2 +; if (VIC.spr_pos[j].y >= 250) break; + lda $d001,x + cmp #250 + bcs @loopexit ; offscreen? +; if (VIC.spr_pos[j].y+22 >= VIC.rasterline) break; + clc + adc #22 + cmp $d012 ; are we done drawing + bcs @loopexit ; this sprite yet? +; VIC.spr_pos[j].y = msprite_y[i]; + lda _msprite_y,y + sta $d001,x +; VIC.spr_pos[j].x = msprite_x[i]; + lda _msprite_x_lo,y + sta $d000,x + ldx j ; X = j +; VIC.spr_color[j] = msprite_color[i]; + lda _msprite_color,y + sta $d027,x +; POKE(0x7f8+j, msprite_shape[i]); + lda _msprite_shape,y + sta $07f8,x +; set hi X bit + lda _msprite_x_hi,y + lsr + lda NOTBITS,x + and $d010 + bcc @nohix + ora BITS,x +@nohix: + sta $d010 ; update X hi bits + inc k ; next object + inx + txa + and #7 + sta j ; next h/w sprite + jmp @loop +@loopexit: +.ifdef DEBUG + lda #0 + sta $d020 +.endif + rts + +; http://selmiak.bplaced.net/games/c64/index.php?lang=eng&game=Tutorials&page=Sprite-Multiplexing +.global _msprite_sort +_msprite_sort: + ldx #$00 +@sortloop: + ldy _msprite_order+1,x + lda _msprite_y,y + ldy _msprite_order,x + cmp _msprite_y,y + bcs @sortskip + stx @sortreload+1 +@sortswap: + lda _msprite_order+1,x + sta _msprite_order,x + tya + sta _msprite_order+1,x + cpx #$00 + beq @sortreload + dex + ldy _msprite_order+1,x + lda _msprite_y,y + ldy _msprite_order,x + cmp _msprite_y,y + bcc @sortswap +@sortreload: + ldx #$00 ; self-modifying code +@sortskip: + inx + cpx #MAX_MSPRITES-1 + bcc @sortloop + rts + +.global _msprite_add_velocity +_msprite_add_velocity: + tay + dey +@loop: + lda _msprite_y_frac,y + clc + adc _msprite_yvel_lo,y + sta _msprite_y_frac,y + lda _msprite_y,y + adc _msprite_yvel_hi,y + sta _msprite_y,y + lda _msprite_x_frac,y + clc + adc _msprite_xvel_lo,y + sta _msprite_x_frac,y + lda _msprite_xvel_hi,y + bmi @xneg + lda _msprite_x_lo,y + adc _msprite_xvel_hi,y + sta _msprite_x_lo,y + lda _msprite_x_hi,y + adc #0 + sta _msprite_x_hi,y + dey + bpl @loop + rts +@xneg: + lda _msprite_x_lo,y + adc _msprite_xvel_hi,y + sta _msprite_x_lo,y + lda _msprite_x_hi,y + adc #$ff + sta _msprite_x_hi,y + dey + bpl @loop + rts + +BITS: + .byte $01,$02,$04,$08,$10,$20,$40,$80 +NOTBITS: + .byte $FE,$FD,$FB,$F7,$EF,$DF,$BF,$7F + +;;;;; + +.data + +j: .res 1 ; h/w sprite index +k: .res 1 ; object index +bailout_line: .res 1 + +.global _msprite_order +.global _msprite_x_lo +.global _msprite_x_hi +.global _msprite_y +.global _msprite_color +.global _msprite_shape +.global _msprite_flags + +_msprite_order: .res MAX_MSPRITES +_msprite_x_lo: .res MAX_MSPRITES +_msprite_x_hi: .res MAX_MSPRITES +_msprite_y: .res MAX_MSPRITES +_msprite_color: .res MAX_MSPRITES +_msprite_shape: .res MAX_MSPRITES +_msprite_flags: .res MAX_MSPRITES + +.global _msprite_x_frac +.global _msprite_xvel_lo +.global _msprite_xvel_hi +.global _msprite_y_frac +.global _msprite_yvel_lo +.global _msprite_yvel_hi + +_msprite_x_frac: .res MAX_MSPRITES +_msprite_xvel_lo: .res MAX_MSPRITES +_msprite_xvel_hi: .res MAX_MSPRITES +_msprite_y_frac: .res MAX_MSPRITES +_msprite_yvel_lo: .res MAX_MSPRITES +_msprite_yvel_hi: .res MAX_MSPRITES diff --git a/presets/c64/musicplayer.c b/presets/c64/musicplayer.c index 90d0740f..43debf06 100644 --- a/presets/c64/musicplayer.c +++ b/presets/c64/musicplayer.c @@ -16,9 +16,7 @@ const int note_table_pal[96] = { // SID utility routines void sid_init() { - SID.flt_freq = 0xff; - SID.flt_ctrl = 0xff; - SID.amp = 0xff; + SID.amp = 0x0f; // volume 15, no filters } #define SID_PULSE_DECAY(voice, period) \ diff --git a/presets/c64/rasterirq.ca65 b/presets/c64/rasterirq.ca65 index e9aca76d..55519b5b 100644 --- a/presets/c64/rasterirq.ca65 +++ b/presets/c64/rasterirq.ca65 @@ -4,18 +4,18 @@ USE_INTERRUPTOR = 0 .segment "DATA" StartDlist: .word NullDlist-1 -NextDlist: .word NullDlist-1 +NextDlist: .word NullDlist-1 .segment "CODE" -.global _dlist_setup +.global ___dlist_setup .global DLIST_IRQ_NEXT .global DLIST_IRQ_RESTART .if USE_INTERRUPTOR .interruptor DLIST_IRQ .endif -_dlist_setup: +___dlist_setup: SEI ; set interrupt bit, make the CPU ignore interrupt requests sta StartDlist+0 ; save XA as pointer to start of dlist diff --git a/presets/c64/rasterirq.h b/presets/c64/rasterirq.h index 087300d1..073873ce 100644 --- a/presets/c64/rasterirq.h +++ b/presets/c64/rasterirq.h @@ -2,15 +2,19 @@ #define _RASTERIRQ_H -void dlist_setup(void* ptr); +// internal function, use macro instead +void __dlist_setup(void* ptr); +// initialize display list with function 'func' #define DLIST_SETUP(func) \ - dlist_setup(((char*)func)-1) + __dlist_setup(((char*)func)-1) +// continue on line 'line' #define DLIST_NEXT(line) \ __A__ = line; \ asm ("jsr DLIST_IRQ_NEXT"); +// restart display list on line 'line' #define DLIST_RESTART(line) \ __A__ = line; \ asm ("jmp DLIST_IRQ_RESTART"); diff --git a/presets/c64/scroll1.c b/presets/c64/scroll1.c index ac704802..c4b62f4f 100644 --- a/presets/c64/scroll1.c +++ b/presets/c64/scroll1.c @@ -2,36 +2,71 @@ #include "common.h" //#link "common.c" -byte x = 0; // x scroll position -byte y = 0; // y scroll position -byte* scrnbuf; // screen buffer +#include + +#define SCROLL_TOP 0 +#define SCROLL_ROWS 10 + +byte scroll_x = 0; // x scroll position + +// return the next character on the right side +// for a given row +char get_char_for_row(byte row) { + return '0' + row; +} + +void draw_right_column() { + // get the top-right corner address of scroll area + word addr = SCRNADR(0x400, 39, SCROLL_TOP); + byte row; + // draw one character per row + for (row=0; row -void main(void) { +#define BUFFER_0 0x400 +#define BUFFER_1 0x3c00 + +byte scroll_x = 0; // x scroll position +byte* scrnbuf[2]; // screen buffer(s) +byte visbuf; // which buffer is visible? 0 or 1 + +void scroll_one_pixel_left() { byte* src; byte* dst; - + // scroll left + scroll_x--; + // set scroll registers + SET_SCROLL_X(scroll_x); + // calculate frame pointers + // source = visible buffer + src = scrnbuf[visbuf] + (scroll_x & 7) * 128; + // destination = hidden buffer + dst = scrnbuf[visbuf ^ 1] + (scroll_x & 7) * 128; + // wait for vsync + waitvsync(); + // scroll hidden buffer + memcpy(dst, src+1, 128); + // every 8 pixels, switch visible and hidden buffers + // and set VIC to point to other buffer + if ((scroll_x & 7) == 0) { + visbuf ^= 1; + SET_VIC_SCREEN(visbuf ? BUFFER_1 : BUFFER_0); + } +} + +void main(void) { clrscr(); - printf("\r\n\r\n\r\n Hello World!"); - printf("\r\n\r\n\r\n This is how we scroll"); - printf("\r\n\r\n\r\n One line at a time"); - printf("\r\n\r\n\r\n And now we have two buffers"); - printf("\r\n\r\n\r\n To copy all the bytes "); + printf("\n\n\n Hello Scrolling World!"); + printf("\n\n\n We scroll in one direction"); + printf("\n\n\n And now we have two buffers"); + printf("\n\n\n And copy hidden -> visible"); + printf("\n\n\n 128 bytes (of 1024) per frame"); + VIC.ctrl1 = 0x10; // 24 lines VIC.ctrl2 = 0x00; // 38 columns - + VIC.bordercolor = COLOR_GRAY1; + // get screen buffer addresses - scrnbuf[0] = (byte*) 0x400; - scrnbuf[1] = (byte*) 0x3c00; - memcpy(scrnbuf[1], scrnbuf[0], 24*40); + scrnbuf[0] = (byte*) BUFFER_0; + scrnbuf[1] = (byte*) BUFFER_1; // infinite loop while (1) { - // scroll left - x--; - // set scroll registers - VIC.ctrl1 = VIC.ctrl1 & 0xf8; - VIC.ctrl1 |= (y & 7); - VIC.ctrl2 = VIC.ctrl2 & 0xf8; - VIC.ctrl2 |= (x & 7); - // calculate frame pointers - src = scrnbuf[frame&1] + (x&7)*128; - dst = scrnbuf[frame&1^1] + (x&7)*128; - // wait for vsync - waitvsync(); - // scroll hidden buffer - memcpy(dst, src+1, 128); - // every 8 pixels, switch farmes - if ((x & 7) == 0) { - VIC.addr = (VIC.addr & 0xf) | ((frame & 1) ? 0x10 : 0xf0); - frame++; - } + scroll_one_pixel_left(); } } diff --git a/presets/c64/scroll3.c b/presets/c64/scroll3.c index 400b677e..c074c58a 100644 --- a/presets/c64/scroll3.c +++ b/presets/c64/scroll3.c @@ -2,44 +2,44 @@ #include "common.h" //#link "common.c" +#include + sbyte scroll_fine_x = 0; sbyte scroll_fine_y = 0; -byte curbuf = 0; byte* scrnbuf[2]; // screen buffer(s) +byte hidbuf = 0; void scroll_update_regs() { - VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | scroll_fine_y; - VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | scroll_fine_x; + SET_SCROLL_X(scroll_fine_x); + SET_SCROLL_Y(scroll_fine_y); } void scroll_swap() { // swap hidden and visible buffers - curbuf ^= 1; + hidbuf ^= 1; // wait for vblank and update registers - wait_vblank(); + waitvsync(); scroll_update_regs(); - VIC.addr = (VIC.addr & 0xf) | (curbuf ? 0x00 : 0x10); - // copy visible buffer to hidden buffer - memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1], COLS*ROWS); + SET_VIC_SCREEN(hidbuf ? 0x8000 : 0x8400); } void scroll_left() { - memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1]+1, COLS*ROWS-1); + memcpy(scrnbuf[hidbuf], scrnbuf[hidbuf^1]+1, COLS*ROWS-1); scroll_swap(); } void scroll_right() { - memcpy(scrnbuf[curbuf]+1, scrnbuf[curbuf^1], COLS*ROWS-1); + memcpy(scrnbuf[hidbuf]+1, scrnbuf[hidbuf^1], COLS*ROWS-1); scroll_swap(); } void scroll_up() { - memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1]+COLS, COLS*(ROWS-1)); + memcpy(scrnbuf[hidbuf], scrnbuf[hidbuf^1]+COLS, COLS*(ROWS-1)); scroll_swap(); } void scroll_down() { - memcpy(scrnbuf[curbuf]+COLS, scrnbuf[curbuf^1], COLS*(ROWS-1)); + memcpy(scrnbuf[hidbuf]+COLS, scrnbuf[hidbuf^1], COLS*(ROWS-1)); scroll_swap(); } @@ -71,29 +71,32 @@ void scroll_setup() { // get screen buffer addresses scrnbuf[0] = (byte*) 0x8000; scrnbuf[1] = (byte*) 0x8400; + // copy existing text to screen 0 memcpy(scrnbuf[0], (byte*)0x400, COLS*ROWS); // copy screen 1 to screen 0 memcpy(scrnbuf[1], scrnbuf[0], COLS*ROWS); - // set VIC bank ($4000-$7FFF) + // set VIC bank // https://www.c64-wiki.com/wiki/VIC_bank - CIA2.pra = 0x01; - - VIC.ctrl1 = 0x10; // 24 lines - VIC.ctrl2 = 0x00; // 38 columns + SET_VIC_BANK(0x8000); + + VIC.ctrl1 &= ~0x08; // 24 lines + VIC.ctrl2 &= ~0x08; // 38 columns } void main(void) { clrscr(); - printf("\r\n\r\n\r\n Hello World!"); - printf("\r\n\r\n\r\n This is how we scroll"); - printf("\r\n\r\n\r\n One line at a time"); - printf("\r\n\r\n\r\n And now we have two buffers"); - printf("\r\n\r\n\r\n To copy all the bytes "); + printf("\n\n\n Hello World!"); + printf("\n\n\n This is how we scroll"); + printf("\n\n\n And now we have two buffers"); + printf("\n\n\n And can go in any direction"); + printf("\n\n\n But we are not incremental"); + printf("\n\n\n And have to pause to scroll and copy"); scroll_setup(); + VIC.bordercolor = COLOR_GRAY1; // install the joystick driver joy_install (joy_static_stddrv); diff --git a/presets/c64/scroll4.c b/presets/c64/scroll4.c index d8dbc5e6..efbc583e 100644 --- a/presets/c64/scroll4.c +++ b/presets/c64/scroll4.c @@ -8,6 +8,8 @@ #include "sprites.h" //#link "sprites.c" +#include + static void draw_cell(word ofs, byte x, byte y) { byte xx = x + origin_x; byte yy = y + origin_y; @@ -57,10 +59,11 @@ void main(void) { // setup scrolling library scroll_setup(); + VIC.bordercolor = 12; // setup sprite library and copy sprite to VIC bank sprite_clear(); - sprite_shape(192, SPRITE1); + sprite_set_shapes(SPRITE1, 192, 1); // install the joystick driver joy_install (joy_static_stddrv); @@ -78,8 +81,6 @@ void main(void) { if (JOY_RIGHT(joy)) scroll_horiz(speed); if (JOY_DOWN(joy)) scroll_vert(speed); // animate sprite in shadow sprite ram - //VIC.ctrl1 |= 0x08; // 24 lines - //VIC.ctrl2 |= 0x08; // 38 columns sprite_draw(0, n++, 70, 192); sprite_draw(0, 172, 145, 192); // wait for vblank diff --git a/presets/c64/scroll5.c b/presets/c64/scroll5.c index 071aa0c5..1899a91b 100644 --- a/presets/c64/scroll5.c +++ b/presets/c64/scroll5.c @@ -8,6 +8,8 @@ #include "sprites.h" //#link "sprites.c" +#include + static void draw_cell(word ofs, byte x, byte y) { byte xx = x + origin_x; byte yy = y + origin_y; @@ -84,10 +86,11 @@ void main(void) { // setup scrolling library scroll_setup(); + VIC.bordercolor = 12; // setup sprite library and copy sprite to VIC bank sprite_clear(); - sprite_shape(192, SPRITE1); + sprite_set_shapes(SPRITE1, 192, 1); sprshad.spr_color[0] = 13; // install the joystick driver diff --git a/presets/c64/scrolling.c b/presets/c64/scrolling.c index b4f5c6f0..6ef5fee5 100644 --- a/presets/c64/scrolling.c +++ b/presets/c64/scrolling.c @@ -15,14 +15,14 @@ byte copy_needed; // -void scroll_swap(void) { +void scroll_swap() { byte* tmp; // swap hidden and visible buffers tmp = hidbuf; hidbuf = visbuf; visbuf = tmp; // set VIC bank address - VIC.addr = (VIC.addr & 0xf) | (((word)visbuf >> 8) << 2); + SET_VIC_SCREEN((word)visbuf); } void copy_color_ram_slow() { @@ -95,9 +95,9 @@ void copy_if_needed() { } } -void scroll_update(void) { - VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | scroll_fine_y; - VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | scroll_fine_x; +void scroll_update() { + SET_SCROLL_X(scroll_fine_x); + SET_SCROLL_Y(scroll_fine_y); if (swap_needed) { scroll_swap(); copy_color_ram_fast(); @@ -108,7 +108,7 @@ void scroll_update(void) { } } -void scroll_left(void) { +void scroll_left() { copy_if_needed(); memmove(hidbuf, hidbuf+1, COLS*ROWS-1); memmove(colorbuf, colorbuf+1, COLS*ROWS-1); @@ -117,7 +117,7 @@ void scroll_left(void) { swap_needed = true; } -void scroll_up(void) { +void scroll_up() { copy_if_needed(); memmove(hidbuf, hidbuf+COLS, COLS*(ROWS-1)); memmove(colorbuf, colorbuf+COLS, COLS*(ROWS-1)); @@ -126,7 +126,7 @@ void scroll_up(void) { swap_needed = true; } -void scroll_right(void) { +void scroll_right() { copy_if_needed(); memmove(hidbuf+1, hidbuf, COLS*ROWS-1); memmove(colorbuf+1, colorbuf, COLS*ROWS-1); @@ -135,7 +135,7 @@ void scroll_right(void) { swap_needed = true; } -void scroll_down(void) { +void scroll_down() { copy_if_needed(); memmove(hidbuf+COLS, hidbuf, COLS*(ROWS-1)); memmove(colorbuf+COLS, colorbuf, COLS*(ROWS-1)); @@ -168,7 +168,7 @@ void scroll_vert(sbyte delta_y) { } } -void scroll_setup(void) { +void scroll_setup() { scroll_fine_x = scroll_fine_y = 0; origin_x = origin_y = 0; swap_needed = true; @@ -185,7 +185,7 @@ void scroll_setup(void) { // set VIC bank ($8000-$BFFF) // https://www.c64-wiki.com/wiki/VIC_bank - CIA2.pra = 0x01; + SET_VIC_BANK(0x8000); // set up 24 line / 38 column mode to hide edges VIC.ctrl1 &= ~0x08; // 24 lines diff --git a/presets/c64/scrolling.h b/presets/c64/scrolling.h index 60dc25ff..26acf31b 100644 --- a/presets/c64/scrolling.h +++ b/presets/c64/scrolling.h @@ -34,6 +34,8 @@ void scroll_draw_row(byte row); /* incremental scrolling library */ extern int pixofs_x; // X scroll pixel offset extern int pixofs_y; // Y scroll pixel offset +extern sbyte fine_correct_x; +extern sbyte fine_correct_y; void scroll_start(byte dir); void scroll_finish(void); diff --git a/presets/c64/siddemo.c b/presets/c64/siddemo.c index 8d98f20c..a09af023 100644 --- a/presets/c64/siddemo.c +++ b/presets/c64/siddemo.c @@ -2,6 +2,8 @@ #include "common.h" //#link "common.c" +#include + //#resource "c64-sid.cfg" #define CFGFILE c64-sid.cfg @@ -9,20 +11,83 @@ //#link "sidplaysfx.ca65" #include "sidplaysfx.h" +static const unsigned char Palette[2] = + { TGI_COLOR_BLUE, TGI_COLOR_WHITE }; + +static int sweep = 0; + +#define BITMAP_START 0xe020 + +// recursive macros to quickly set bitmap memory +#define SID_SIGNAL_4(index) \ + POKE(BITMAP_START + (index) + 0, SID.noise); \ + POKE(BITMAP_START + (index) + 1, SID.noise); \ + POKE(BITMAP_START + (index) + 2, SID.noise); \ + POKE(BITMAP_START + (index) + 3, SID.noise); + +#define SID_SIGNAL_16(index) \ + SID_SIGNAL_4(index); \ + SID_SIGNAL_4(index+4); \ + SID_SIGNAL_4(index+8); \ + SID_SIGNAL_4(index+12); + +#define SID_SIGNAL_64(index) \ + SID_SIGNAL_16(index); \ + SID_SIGNAL_16(index+16); \ + SID_SIGNAL_16(index+32); \ + SID_SIGNAL_16(index+48); + +void show_signal() { + // push SID voice 3 signal to screen memory + // as fast as we can + SID_SIGNAL_64(0); + SID_SIGNAL_64(64); + SID_SIGNAL_64(128); + SID_SIGNAL_64(192); +} + +void show_envelope() { + // read envelope value and plot vertical lines + // via TGI library + byte value = 199 - (SID.read3 >> 1); + tgi_setcolor(0); + tgi_line(sweep, 199 - 128, sweep, value - 1); + tgi_setcolor(1); + tgi_line(sweep, value, sweep, 240); + if (++sweep == 320) sweep = 0; +} + void main(void) { - clrscr(); - cursor(0); - joy_install(joy_static_stddrv); + // install TGI graphics driver + tgi_install(tgi_static_stddrv); + tgi_init(); + tgi_clear(); + tgi_setpalette(Palette); + + // initialize SID player sid_init(0); sid_start(); - printf("\r\nSID file loaded at $1000\r\n"); - printf("\r\nMove joystick for SFX\r\n"); + + // install joystick driver + joy_install(joy_static_stddrv); + while (1) { - char joy = joy_read(0); + // play sound effect when joystick is moved + byte joy = joy_read(0); if (joy) { sid_sfx(joy & 3); + // exit when fire button pressed + if (JOY_BTN_1(joy)) { break; } } + // sync with frame rate waitvsync(); + // update SID player sid_update(); + // update graphs + show_envelope(); + show_signal(); } + + tgi_uninstall(); + sid_stop(); } diff --git a/presets/c64/side_scroller.c b/presets/c64/side_scroller.c new file mode 100644 index 00000000..ce7e0807 --- /dev/null +++ b/presets/c64/side_scroller.c @@ -0,0 +1,341 @@ + +#include "common.h" +//#link "common.c" + +#include "sprites.h" +//#link "sprites.c" + +#include "rasterirq.h" +//#link "rasterirq.ca65" + +#include "bcd.h" +//#link "bcd.c" + +#include "sidmacros.h" + +///// SPRITE DATA + +#define NUM_SPRITE_PATTERNS 4 + +/*{w:12,h:21,bpp:2,brev:1,wpimg:64,count:4,aspect:2}*/ +const char SPRITE_DATA[64*NUM_SPRITE_PATTERNS] = { + 0x0A,0xAA,0x80,0x0A,0xAA,0x80,0x2A,0xAA, + 0xA0,0x2A,0xAA,0xA0,0xAA,0xAA,0xA8,0xFF, + 0xD5,0x40,0xCD,0xD7,0x40,0x3D,0xD5,0x54, + 0x37,0x55,0x54,0x37,0x54,0x50,0x05,0x55, + 0x00,0x3A,0xA0,0x00,0xEA,0xA8,0x00,0xAB, + 0xAA,0x00,0xAB,0xAA,0x00,0xAB,0xAA,0x80, + 0xAA,0xEA,0x80,0xAA,0xAA,0x80,0x0F,0xFC, + 0x00,0x0F,0xFC,0x00,0x0F,0xFF,0xC0,0x00, + + 0x02,0xAA,0xA0,0x02,0xAA,0xA0,0x0A,0xAA, + 0xA8,0x0A,0xAA,0xA8,0x2A,0xAA,0xAA,0x01, + 0x57,0xFF,0x01,0xD7,0x73,0x15,0x57,0x7C, + 0x15,0x55,0xDC,0x05,0x15,0xDC,0x00,0x55, + 0x50,0x00,0x0A,0xAC,0x00,0x2A,0xAB,0x00, + 0xAA,0xEA,0x00,0xAA,0xEA,0x02,0xAA,0xEA, + 0x02,0xAB,0xAA,0x02,0xAA,0xAA,0x00,0x3F, + 0xF0,0x00,0x3F,0xF0,0x03,0xFF,0xF0,0x00, + + 0x03,0xFF,0xF0,0x0E,0xAA,0xAC,0x0E,0xAA,0xAC, + 0x3A,0xAE,0xAB,0x3A,0xBB,0xAB,0x3A,0xBA,0xAB, + 0x3A,0xBB,0xAB,0x3A,0xAE,0xAB,0x3A,0xAA,0xAB, + 0x35,0xAA,0x97,0x04,0x6A,0x44,0x04,0x15,0x04, + 0x01,0x04,0x10,0x01,0x04,0x10,0x01,0x04,0x10, + 0x00,0x44,0x40,0x00,0x44,0x40,0x00,0xEA,0xC0, + 0x00,0xD9,0xC0,0x00,0xE6,0xC0,0x00,0x3F,0x00, + 0x00, + + 0x00,0x00,0x00,0x00,0xFF,0x00,0x03,0xAA, + 0xC0,0x0E,0xAA,0xB0,0x3A,0xAA,0xAC,0xE9, + 0x69,0x6B,0xEA,0x69,0xAB,0xEA,0xAA,0xAB, + 0xEA,0xAA,0xAB,0x3A,0x96,0xAC,0x3A,0x69, + 0xAC,0x0E,0xAA,0xB0,0x0E,0xAA,0xB0,0x0F, + 0xAA,0xF0,0x3A,0xAA,0xAC,0xEE,0xAA,0xBB, + 0xEE,0xAA,0xBB,0x33,0xAA,0xCC,0x03,0xAB, + 0x00,0x00,0xEB,0x00,0x00,0x3F,0xC0,0x00, +}; + +///// DEFINES + +#define GAME_BASE 0x400 +#define SCORE_BASE 0x2c00 + +#define SPRITE_SHAPE 192 // first sprite shape # +#define PLAYER_SHAPE SPRITE_SHAPE +#define POWERUP_SHAPE (SPRITE_SHAPE+2) +#define OBSTACLE_SHAPE (SPRITE_SHAPE+3) + +#define PLAYER_INDEX 0 // sprite indices +#define POWERUP_INDEX 1 +#define OBSTACLE_INDEX 2 + +#define CENTER_X 172 // sprite start X coord. +#define FLOOR_Y (128 << 8) // sprite start Y (fixed 8.8) +#define JUMP_VELOCITY (-900) // jump velocity (fixed 8.8) +#define GRAVITY 32 // gravity (fixed 8.8) + +#define POWERUP_Y 80 // sprite Y of power up +#define OBSTACLE_Y 96 // sprite Y of obstacle + +#define SCROLL_TOP 8 // scroll top row +#define SCROLL_ROWS 14 // scroll # of rows +#define GROUND_ROW 7 // ground row (+ top row) + +///// VARIABLES + +word player_x; // player X +word player_y; // player Y (fixed 8.8) +signed int player_vel_y; // player Y velocity (fixed 8.8) +byte faceleft = 0; // 0 = face right, 1 = face left +word scroll_x = 0; // current scroll X position +word score = 0; // current player score + +///// FUNCTIONS + +// display list used by rasterirq.h +// draws scoreboard and sets scroll register +void display_list() { + // set x scroll register to scroll value + SET_SCROLL_X(scroll_x); + // set background color + VIC.bgcolor[0] = COLOR_CYAN; + // next interrupt is two rows from bottom + DLIST_NEXT(248-16); + + // set background color + VIC.bgcolor[0] = COLOR_BLUE; + // screen memory = 0x2800 + SET_VIC_SCREEN(SCORE_BASE); + // clear x scroll register + SET_SCROLL_X(0); + // next interrupt is bottom of frame + DLIST_NEXT(250); + + // reset screen to 0x400 + SET_VIC_SCREEN(0x400); + // next interrupt is above top of next frame + DLIST_RESTART(40); +} + +void update_scoreboard() { + draw_bcd_word(SCRNADR(SCORE_BASE,7,24), score); +} + +void add_score(int delta) { + score = bcd_add(score, delta); +} + +// clear scoreboard and draw initial strings +void init_scoreboard() { + memset((void*)SCORE_BASE, ' ', 1024); + memcpy((void*)SCRNADR(SCORE_BASE,1,24), "SCORE:", 6); + update_scoreboard(); +} + +void init_sprite_shapes() { + sprite_set_shapes(SPRITE_DATA, + SPRITE_SHAPE, + NUM_SPRITE_PATTERNS); +} + +void init_sprite_positions() { + // setup sprite positions + player_x = CENTER_X; + player_y = FLOOR_Y; + player_vel_y = 0; + sprshad.spr_color[POWERUP_INDEX] = COLOR_YELLOW; + sprshad.spr_color[OBSTACLE_INDEX] = COLOR_GRAY3; +} + +void move_player(byte joy) { + // move sprite based on joystick + if (JOY_LEFT(joy)) { + player_x -= 2; + faceleft = 1; + } + if (JOY_RIGHT(joy)) { + player_x += 1; + faceleft = 0; + } + if (JOY_BTN_1(joy) && player_y == FLOOR_Y) { + player_vel_y = JUMP_VELOCITY; + } + + // apply velocity + player_y += player_vel_y; + // apply gravity + player_vel_y += GRAVITY; + // stop velocity when falling thru floor + if (player_y >= FLOOR_Y) { + player_y = FLOOR_Y; // reset Y position + player_vel_y = 0; // reset velocity + } + + // keep player from moving offscreen + if (player_x < 36) player_x = 36; + if (player_x > 300) player_x = 300; + + // draw player into sprite shadow buffer + sprite_draw(PLAYER_INDEX, + player_x, + player_y >> 8, // fixed point conversion + PLAYER_SHAPE + faceleft); +} + +void move_items() { + // move in sync with scrolling world + // draw powerup + sprite_draw(POWERUP_INDEX, + ((scroll_x*2) & 0x1ff), + POWERUP_Y, + POWERUP_SHAPE); + // draw obstacle + sprite_draw(OBSTACLE_INDEX, + ((scroll_x+256) & 0x1ff), + OBSTACLE_Y, + OBSTACLE_SHAPE); +} + +byte get_char_for_row(byte row) { + // ground? + if (row >= GROUND_ROW) { return 253; } + // obstacle? + if (row >= GROUND_ROW-3) { + // only show obstacle for certain values of scroll_x + if ((scroll_x & 0b1110000) == 0) { return 247; } + } + // default is the sky (empty space) + return 32; +} + +void draw_right_column() { + // get the top-right corner address of scroll area + word addr = SCRNADR(GAME_BASE, 39, SCROLL_TOP); + byte row; + // draw one character per row + for (row=0; row #include +#include "common.h" +//#link "common.c" + void main(void) { clrscr(); printf("\nHello World!\n"); diff --git a/presets/c64/sprite_collision.c b/presets/c64/sprite_collision.c index c456b88d..a0ff5e99 100644 --- a/presets/c64/sprite_collision.c +++ b/presets/c64/sprite_collision.c @@ -16,8 +16,12 @@ const char SPRITEMC[3*21] = { 0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00 }; -int xpos[8]; -int ypos[8]; +#define SPRITE_SHAPE 192 + +// X/Y position arrays +int xpos[8]; // fixed point 9.7 +int ypos[8]; // fixed point 8.8 +// X/Y velocity arrays int xvel[8]; int yvel[8]; @@ -25,7 +29,7 @@ void init_sprites(void) { byte i; // setup sprite positions for (i=0; i<8; i++) { - xpos[i] = ((i & 3) * 0x2000) - 0x1000; + xpos[i] = ((i & 3) * 0x2000) - 0x3000; ypos[i] = (i * 0x1000) - 0x3000; sprshad.spr_color[i] = i | 8; } @@ -35,7 +39,10 @@ void move_sprites(void) { byte i; for (i=0; i<8; i++) { //VIC.bordercolor = i; - sprite_draw(i, (xpos[i]>>7)+0x80, (ypos[i]>>8)+0x80, 192); + sprite_draw(i, + (xpos[i] >> 7) + 172, + (ypos[i] >> 8) + 145, + SPRITE_SHAPE); // update position xpos[i] += xvel[i]; ypos[i] += yvel[i]; @@ -71,11 +78,11 @@ void collide_sprites(byte spr_coll) { } } -void iterategame1(void) { +void iterate_game(void) { byte spr_coll; - + // wait for vblank - wait_vblank(); + waitvsync(); // grab and reset sprite-sprite collision flags spr_coll = VIC.spr_coll; // then update sprite registers from shadow RAM @@ -89,36 +96,6 @@ void iterategame1(void) { collide_sprites(spr_coll); } -void iterategame2(void) { - byte spr_coll; - - // FIRST FRAME: move and update velocity - wait_vblank(); - // grab and reset sprite-sprite collision flags - spr_coll = VIC.spr_coll; - // then update sprite registers from shadow RAM - sprite_update(DEFAULT_SCREEN); - // draw sprites into shadow ram - // and update posiitons - move_sprites(); - // and update velocities - update_sprites(); - - // SECOND FRAME: move and process collisions - wait_vblank(); - // grab and reset sprite-sprite collision flags - // combine with previous frame flags - spr_coll |= VIC.spr_coll; - // then update sprite registers from shadow RAM - sprite_update(DEFAULT_SCREEN); - // draw sprites into shadow ram - // and update posiitons - move_sprites(); - // if any flags are set in the collision register, - // process sprite collisions - collide_sprites(spr_coll); -} - void main(void) { clrscr(); @@ -126,7 +103,7 @@ void main(void) { // setup sprite library and copy sprite to VIC bank sprite_clear(); - sprite_shape(192, SPRITEMC); + sprite_set_shapes(SPRITEMC, SPRITE_SHAPE, 1); // set colors sprshad.spr_mcolor = 0xff; @@ -138,7 +115,7 @@ void main(void) { // game loop while (1) { - iterategame2(); + iterate_game(); } } diff --git a/presets/c64/sprite_test.c b/presets/c64/sprite_test.c deleted file mode 100644 index d07f2cd1..00000000 --- a/presets/c64/sprite_test.c +++ /dev/null @@ -1,42 +0,0 @@ - -#include "common.h" - -/*{w:24,h:21,bpp:1,brev:1,count:1}*/ -const char SPRITE_DATA[64] = { - 0x0f,0xff,0x80,0x17,0xff,0x40,0x2b,0xfe, - 0xa0,0x7f,0xff,0xf0,0xff,0xc0,0x3f,0xe0, - 0x3f,0xc0,0x17,0xbe,0xc0,0x2d,0x7f,0xf0, - 0x2b,0x7f,0xf8,0x2a,0xff,0xf8,0x15,0xf6, - 0x00,0x3f,0xf8,0x00,0xfd,0xfc,0x00,0xfd, - 0xff,0x00,0xfe,0xff,0x80,0xff,0x7f,0xc0, - 0xff,0xff,0xc0,0xff,0xff,0xc0,0x0a,0xa8, - 0x00,0x0f,0xf8,0x00,0x0f,0xff,0x80,0x03, -}; - -/*{w:12,h:21,bpp:2,brev:1,count:1,aspect:2}*/ -const char SPRITE_MC_DATA[64] = { - 0x0a,0xaa,0x80,0x0a,0xaa,0x80,0x2a,0xaa, - 0xa0,0x2a,0xaa,0xa0,0xaa,0xaa,0xaa,0xff, - 0xd5,0x40,0x0d,0xd7,0x40,0x3d,0xd5,0x54, - 0x37,0x55,0x54,0x37,0x55,0x54,0x35,0x55, - 0x00,0x3a,0xa0,0x00,0xea,0xa8,0x00,0xab, - 0xaa,0x00,0xab,0xaa,0x00,0xab,0xaa,0x80, - 0xaa,0xea,0x80,0xaa,0xaa,0x80,0x0f,0xfc, - 0x00,0x0f,0xfc,0x00,0x0f,0xff,0xc0,0x83, -}; - -void main(void) { - // clear the screen - clrscr(); - // copy sprite pattern to RAM address 0x3800 - memcpy((char*)0x3800, SPRITE_DATA, sizeof(SPRITE_DATA)); - // set sprite #0 shape entry (224) - POKE(0x400 + 0x3f8, 0x3800 / 64); - // set X and Y coordinate for sprite #0 - VIC.spr_pos[0].x = 172; - VIC.spr_pos[0].y = 145; - // set color for sprite #0 - VIC.spr_color[0] = COLOR_GREEN; - // enable sprite #0 - VIC.spr_ena = 0b00000001; -} diff --git a/presets/c64/sprites.c b/presets/c64/sprites.c index c0822884..96c31802 100644 --- a/presets/c64/sprites.c +++ b/presets/c64/sprites.c @@ -8,7 +8,7 @@ void sprite_clear(void) { memset(&sprshad, 0, sizeof(sprshad)); } -void sprite_update(char* screenmem) { +void sprite_update(byte* screenmem) { memcpy(screenmem + 0x3f8, sprshad.spr_shapes, 8); memcpy(VIC.spr_pos, sprshad.spr_pos, 16); memcpy(VIC.spr_color, sprshad.spr_color, 8); @@ -20,10 +20,13 @@ void sprite_update(char* screenmem) { VIC.spr_mcolor = sprshad.spr_mcolor; } -void sprite_shape(byte index, const char* sprite_data) { +void sprite_set_shapes(const void* sprite_data, + byte index, + byte count) +{ memcpy(get_vic_bank_start() + index * 64, sprite_data, - 64); + 64 * count); } const byte BITS[8] = { diff --git a/presets/c64/sprites.h b/presets/c64/sprites.h index 54f1d43e..400ab13b 100644 --- a/presets/c64/sprites.h +++ b/presets/c64/sprites.h @@ -3,7 +3,7 @@ #include "common.h" -typedef struct { +typedef struct SpriteShadow { struct { byte x; /* X coordinate */ byte y; /* Y coordinate */ @@ -18,12 +18,25 @@ typedef struct { byte spr_shapes[8]; /* sprite shapes */ } SpriteShadow; +/* sprite shadow buffer */ extern SpriteShadow sprshad; -void sprite_clear(void); -void sprite_update(char* screenmem); -void sprite_shape(byte index, const char* sprite_data); -void sprite_draw(byte i, word x, byte y, byte shape); -byte sprite_get_closest_collision(byte i, byte spr_coll); +/* set one or more sprite patterns from a byte array */ +void sprite_set_shapes(const void* sprite_data, + byte index, + byte count); +/* clear all sprites from shadow buffer */ +void sprite_clear(); +/* draw a sprite into shadow buffer */ +void sprite_draw(byte index, word x, byte y, byte shape); +/* update sprite registers */ +void sprite_update(byte* screenmem); + +/* get the closest sprite collision + given the set of collision flags */ +byte sprite_get_closest_collision(byte index, byte spr_coll); + +// bit lookup table +extern const byte BITS[8]; #endif diff --git a/presets/c64/spritesinborder.c b/presets/c64/spritesinborder.c index ab7ce4a2..cb8ceb94 100644 --- a/presets/c64/spritesinborder.c +++ b/presets/c64/spritesinborder.c @@ -21,21 +21,28 @@ const char spriteshape[3*21] = { 0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00 }; +byte scroll_x = 0; + void dlist_example(void) { - static byte i = 0; - VIC.bordercolor = 6; VIC.bordercolor = 5; VIC.ctrl1 = 0x18; + VIC.ctrl2 = VIC.ctrl2 & 0xf8; + VIC.ctrl2 |= (scroll_x & 7); DLIST_NEXT(150); // VIC.ctrl1 = 5 | 0x18; VIC.bordercolor = 2; + sprshad.spr_pos[0].y += 1; + scroll_x++; + VIC.addr ^= 0xf0; + VIC.ctrl2 = VIC.ctrl2 & 0xf8; DLIST_NEXT(0xf9); VIC.ctrl1 = 0x10; VIC.bordercolor = 3; + VIC.addr ^= 0xf0; DLIST_NEXT(0xfc); VIC.ctrl1 = 0x18; @@ -49,7 +56,7 @@ void main(void) { clrscr(); sprite_clear(); - sprite_shape(192, spriteshape); + sprite_set_shapes(spriteshape, 192, 1); // set colors sprshad.spr_exp_x = 0xff; @@ -61,8 +68,8 @@ void main(void) { DLIST_SETUP(dlist_example); while (1) { - sprshad.spr_pos[0].y += 1; + waitvsync(); sprite_update(DEFAULT_SCREEN); - printf("Hello World! "); + printf("Raster IRQ-driven display list! "); } } diff --git a/presets/c64/test_multiplex.c b/presets/c64/test_multiplex.c new file mode 100644 index 00000000..9b7a1097 --- /dev/null +++ b/presets/c64/test_multiplex.c @@ -0,0 +1,136 @@ + +#include "common.h" +//#link "common.c" + +#include "sprites.h" +//#link "sprites.c" + +#define NUM_SPRITE_PATTERNS 2 +#define SPRITE_SHAPE 192 +#define SPRITES_PER_ROW 6 + +/*{w:12,h:21,bpp:2,brev:1,count:2}*/ +const char SPRITEMC[64*NUM_SPRITE_PATTERNS] = { + 0x00,0xAA,0x80,0x02,0xAA,0xA0,0x0A,0xAA,0xA8, + 0x0A,0xAE,0xA8,0x0A,0xBB,0xA8,0x0A,0xBA,0xA8, + 0x0A,0xBB,0xA8,0x0A,0xAE,0xA8,0x0A,0xAA,0xA8, + 0x09,0xAA,0x98,0x08,0x6A,0x48,0x08,0x1D,0x08, + 0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20, + 0x00,0x8C,0x80,0x00,0x8C,0x80,0x00,0x55,0x40, + 0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00, + 0, + 0x00,0xAE,0x80,0x02,0xBF,0xA0,0x0B,0xBF,0xB8, + 0x0B,0xBF,0xB8,0x0B,0xBF,0xB8,0x0B,0xBF,0xB8, + 0x0B,0xBF,0xB8,0x0B,0xBF,0xB8,0x0B,0xAE,0xB8, + 0x09,0xAE,0x98,0x08,0x6E,0x48,0x08,0x1D,0x08, + 0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20, + 0x08,0x8C,0x88,0x08,0x8C,0x88,0x20,0x55,0x42, + 0x20,0x77,0x42,0x20,0x5D,0x42,0x20,0x15,0x02, + 0, +}; + +SpriteShadow* sprite_rows[3]; // row sprite buffers +int player_x = 172; // player X coordinate +byte player_y = 222; // player Y coordinate + +void init_sprites(void) { + byte row,i; + // iterate through each row of sprites + for (row=0; row<3; row++) { + // fill in data for local sprite buffer + sprite_clear(); + sprshad.spr_mcolor = 0xff; + for (i=0; ispr_pos[index].x; + byte mask = BITS[index]; // lookup table for (1 << index) + if (spr->spr_hi_x & mask) { + x |= 0x100; + } + x += delta_x; + spr->spr_pos[index].x = x; + if (x & 0x100) { + spr->spr_hi_x |= mask; + } else { + spr->spr_hi_x &= ~mask; + } +} + +void move_sprites() { + byte i; + for (i=0; i>8; + msprite_y[i] = i*0+50; +// msprite_flags[i] = 0; + msprite_shape[i] = 255; + msprite_color[i] = i|8; + } +} + +void display_list() { + msprite_render_init(); + msprite_render_section(); + DLIST_NEXT(Y1+YS*1); + msprite_render_section(); + DLIST_NEXT(Y1+YS*2); + msprite_render_section(); + DLIST_NEXT(Y1+YS*3); + msprite_render_section(); + DLIST_NEXT(Y1+YS*4); + msprite_render_section(); + DLIST_NEXT(Y1+YS*5); + msprite_render_section(); + VIC.bordercolor = 3; + msprite_sort(); + VIC.bordercolor = 4; + msprite_add_velocity(NUM_TEST_SPRITES); + VIC.bordercolor = 0; + DLIST_RESTART(Y0); +} + +void msprite_set_position(byte index, int x, byte y) { + asm("sei"); + msprite_x_lo[index] = x; + msprite_x_hi[index] = x >> 8; + msprite_y[index] = y; + asm("cli"); +} + +void msprite_add_position(byte index, byte dx, byte dy) { + int x; + x = msprite_x_lo[index] | msprite_x_hi[index]*256; + x += dx; + asm("sei"); + msprite_x_lo[index] = x; + msprite_x_hi[index] = x >> 8; + msprite_y[index] += dy; + asm("cli"); +} + +void apply_gravity() { + byte i; + for (i=0; i> 8; + msprite_yvel_lo[i] = yvel; + msprite_yvel_hi[i] = yvel >> 8; + } +} + +void do_test() { + byte i; + raster_wait(160); + for (i=0; i extends BaseDebugPl pause() { this.timer.stop(); this.audio && this.audio.stop(); - // i guess for runToVsync()? - if (this.probeRecorder) { - this.probeRecorder.singleFrame = true; - } - } - // so probe views stick around TODO: must be a better way? - runToVsync() { - if (this.probeRecorder) { - this.probeRecorder.clear(); - this.probeRecorder.singleFrame = false; - } - super.runToVsync(); } -// TODO: reset target clock counter + // so probe views stick around TODO: must be a better way? + runToVsync() { + this.restartDebugging(); + var flag = false; + this.runEval( () : boolean => { + if (this.getRasterScanline() > 0) flag = true; + else return flag; + }); + } + + // TODO: reset target clock counter getRasterScanline() { return isRaster(this.machine) && this.machine.getRasterY(); } diff --git a/src/machine/c64.ts b/src/machine/c64.ts index e2426b8d..5d2216bc 100644 --- a/src/machine/c64.ts +++ b/src/machine/c64.ts @@ -77,7 +77,8 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab } advanceFrame(trap: TrapCondition) : number { // TODO: does this sync with VSYNC? - var scanline = this.getRasterLine(); + // TODO: ticks, not msec (machine_tick() has different rate then machine_exec()) + var scanline = this.getRasterY(); var clocks = Math.floor((this.numTotalScanlines - scanline) * (19656+295) / this.numTotalScanlines); var probing = this.probe != null; if (probing) this.exports.machine_reset_probe_buffer(); @@ -102,6 +103,7 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab V:s[10] & 64, N:s[10] & 128, o:this.readConst(pc), + R:s[19] != 0x37, // bit 28 of PINS } } saveState() { @@ -179,7 +181,7 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab } this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1); } - getRasterLine() { + getRasterY() { return this.exports.machine_get_raster_line(this.sys); } getDebugStateOffset(index: number) { @@ -223,7 +225,7 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab let screen = vicbank + (state.vic[0x18] >> 4) * 0x400; let isbitmap = state.vic[0x11] & 0x20; let ischar = (state.cia2[0]&1)==1 && (state.vic[0x18]&12)==4; - s += `Scanline: ${lpad(this.getRasterLine(),3)} `; + s += `Scanline: ${lpad(this.getRasterY(),3)} `; if (state.vic[0x11] & 0x20) s += ' BITMAP'; else s += ' CHAR'; if (state.vic[0x16] & 0x10) s += ' MULTICOLOR'; if (state.vic[0x11] & 0x40) s += ' EXTENDED'; diff --git a/src/machine/cpc.ts b/src/machine/cpc.ts index 567fc5e1..83fda7fa 100644 --- a/src/machine/cpc.ts +++ b/src/machine/cpc.ts @@ -58,7 +58,7 @@ export class CPC_WASMMachine extends BaseWASMMachine implements Machine { } } advanceFrame(trap: TrapCondition) : number { - var scanline = this.getRasterLine(); + var scanline = this.getRasterY(); var clocks = Math.floor((this.numTotalScanlines - scanline) * 19965 / this.numTotalScanlines); var probing = this.probe != null; if (probing) this.exports.machine_reset_probe_buffer(); @@ -66,7 +66,7 @@ export class CPC_WASMMachine extends BaseWASMMachine implements Machine { if (probing) this.copyProbeData(); return clocks; } - getRasterLine() { + getRasterY() { return this.exports.machine_get_raster_line(this.sys); } /* diff --git a/src/machine/vic20.ts b/src/machine/vic20.ts index 4e394b88..1e760813 100644 --- a/src/machine/vic20.ts +++ b/src/machine/vic20.ts @@ -73,7 +73,7 @@ export class VIC20_WASMMachine extends BaseWASMMachine implements Machine, Probe } advanceFrame(trap: TrapCondition) : number { // TODO: does this sync with VSYNC? - var scanline = this.getRasterLine(); + var scanline = this.getRasterY(); var clocks = Math.floor((this.numTotalScanlines - scanline) * (19656+295+32) / this.numTotalScanlines); var probing = this.probe != null; if (probing) this.exports.machine_reset_probe_buffer(); @@ -81,7 +81,7 @@ export class VIC20_WASMMachine extends BaseWASMMachine implements Machine, Probe if (probing) this.copyProbeData(); return clocks; } - getRasterLine() { + getRasterY() { return this.exports.machine_get_raster_line(this.sys); } getCPUState() { diff --git a/src/platform/c64.ts b/src/platform/c64.ts index d52bf947..9e1ac6ae 100644 --- a/src/platform/c64.ts +++ b/src/platform/c64.ts @@ -6,23 +6,26 @@ import { BaseMAME6502Platform } from "../common/mameplatform"; const C64_PRESETS = [ {id:'hello.dasm', name:'Hello World (ASM)'}, - {id:'eliza.c', name:'Eliza (C)'}, - {id:'tgidemo.c', name:'TGI Graphics Demo (C)'}, - {id:'upandaway.c', name:'Up, Up and Away (C)'}, - {id:'sprite_test.c', name:'Sprite Setup (C)'}, - {id:'joymove.c', name:'Joystick Movement (C)'}, - {id:'siegegame.c', name:'Siege Game (C)'}, - {id:'scroll1.c', name:'Scrolling 1 (C)'}, - {id:'scroll2.c', name:'Scrolling 2 (C)'}, - {id:'scroll3.c', name:'Scrolling 3 (C)'}, - {id:'scroll4.c', name:'Scrolling 4 (C)'}, - {id:'scroll5.c', name:'Scrolling 5 (C)'}, - {id:'sprite_collision.c', name:'Sprite Collision (C)'}, - {id:'multilines.c', name:'Multicolor Lines+Flood Fill (C)'}, - {id:'musicplayer.c', name:'Music Player (C)'}, + {id:'23matches.c', name:'23 Matches'}, + {id:'tgidemo.c', name:'TGI Graphics Demo'}, + {id:'upandaway.c', name:'Up, Up and Away'}, + {id:'siegegame.c', name:'Siege Game'}, + {id:'joymove.c', name:'Sprite Movement'}, + {id:'sprite_collision.c', name:'Sprite Collision'}, + {id:'test_multiplex.c', name:'Sprite Multiplexing'}, + {id:'scroll1.c', name:'Scrolling (Single Buffer)'}, + {id:'scroll2.c', name:'Scrolling (Double Buffer)'}, + {id:'scroll3.c', name:'Scrolling (Multidirectional)'}, + {id:'scroll4.c', name:'Scrolling (Color RAM Buffering)'}, + {id:'scroll5.c', name:'Scrolling (Camera Following)'}, + {id:'side_scroller.c', name:'Side-Scrolling Game'}, + {id:'fullscrollgame.c', name:'Full-Scrolling Game'}, + {id:'mcbitmap.c', name:'Multicolor Lines+Flood Fill'}, + //{id:'mandel.c', name:'Mandelbrot Fractal'}, + {id:'musicplayer.c', name:'Music Player'}, {id:'sidtune.dasm', name:'Tiny SID Tune (ASM)'}, - {id:'siddemo.c', name:'SID Demo (C)'}, - {id:'climber.c', name:'Climber Game (C)'}, + {id:'siddemo.c', name:'SID Player Demo'}, + {id:'climber.c', name:'Climber Game'}, ]; const C64_MEMORY_MAP = { main:[ diff --git a/test/cli/testworker.js b/test/cli/testworker.js index 73ba5d6d..a558a134 100644 --- a/test/cli/testworker.js +++ b/test/cli/testworker.js @@ -243,6 +243,7 @@ describe('Worker', function() { }); it('should compile C64 cc65 skeleton', function(done) { var csource = ab2str(fs.readFileSync('presets/c64/skeleton.cc65')); + csource = csource.replace('#include "','//'); compile('cc65', csource, 'c64.wasm', done, 3001, 3, 0); }); it('should compile zmachine inform6 skeleton', function(done) {