c64: presets, new vsync

This commit is contained in:
Steven Hugg 2022-08-11 15:27:20 -05:00
parent 340ef9a4bc
commit 472b9f952d
41 changed files with 2122 additions and 355 deletions

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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<NUM_SPRITE_PATTERNS; i++) {
sprite_shape(SPRITE_SHAPE_FIRST+i, SPRITE_DATA[i]);
}
sprite_set_shapes(SPRITE_DATA, SPRITE_SHAPE_FIRST, NUM_SPRITE_PATTERNS);
sprshad.spr_mcolor = 0xff;
VIC.spr_mcolor0 = 0x0f;
VIC.spr_mcolor1 = 0x00;

View File

@ -13,6 +13,16 @@ static byte VIC_BANK_PAGE[4] = {
0xc0, 0x80, 0x40, 0x00
};
char* get_vic_bank_start(void) {
char* get_vic_bank_start() {
return (char*)(VIC_BANK_PAGE[CIA2.pra & 3] << 8);
}
char* get_screen_memory() {
return ((VIC.addr & 0xf0) << 6) + get_vic_bank_start();
}
char __fastcall__ poll_keyboard() {
asm("jmp $f142");
return __A__;
}

View File

@ -10,20 +10,71 @@
#include <c64.h>
#include <joystick.h>
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

View File

@ -0,0 +1,616 @@
#include <stdio.h>
#include <conio.h>
#include <c64.h>
#include <cbm_petscii_charmap.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <joystick.h>
//#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; y<MAP_ROWS; y++) {
for (x=0; x<MAP_COLS; x++) {
if (get_cell_at(x*4, y*4))
tileflagmap[i++] = compute_tile_flags();
}
}
}
static void draw_cell(word ofs, byte scrn_x, byte scrn_y) {
byte ch, color;
if (get_cell_at(scrn_x + origin_x, scrn_y + origin_y)) {
ch = tilechar;
color = chartileset_colour_data[tileindex];
} else {
ch = DEFAULT_CHAR;
color = DEFAULT_COLOR;
}
hidbuf[ofs] = ch;
colorbuf[ofs] = color;
}
void scroll_draw_column(byte col) {
byte y;
word ofs = col;
for (y=0; y<ROWS; y++) {
draw_cell(ofs, col, y);
ofs += COLS;
}
}
void scroll_draw_row(byte row) {
byte x;
word ofs = row * COLS;
for (x=0; x<COLS; x++) {
draw_cell(ofs, x, row);
++ofs;
}
}
#define NUM_SPRITE_PATTERNS 13
/*{w:12,h:21,bpp:2,brev:1,count:13,aspect:2}*/
const char SPRITE_DATA[NUM_SPRITE_PATTERNS][64] = {
// left direction
{
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xEA,0x00,
0x02,0xEA,0x00,0x02,0xEA,0x00,0x02,0xEA,0x00,
0x00,0xA8,0x50,0x00,0x15,0x50,0x00,0xAA,0x50,
0x00,0xAA,0x50,0x00,0xAA,0x50,0x0A,0xAA,0x50,
0x02,0xAA,0x50,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0xAA,0x00,0x00,0xA2,0x80,0x00,0xA2,0x80,
0x00,0x22,0x80,0x01,0x51,0x40,0x01,0x51,0x40
},
{
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xAA,0x00,
0x02,0xAA,0x00,0x22,0xAA,0x00,0x22,0xAA,0x00,
0x20,0xA8,0x00,0x28,0x54,0x00,0x2A,0x56,0x80,
0x0A,0x56,0xA0,0x02,0x56,0xA0,0x02,0x56,0x20,
0x02,0x56,0x20,0x03,0xFF,0x20,0x02,0xAA,0x00,
0x02,0x8A,0x00,0x02,0x8A,0x00,0x01,0x4A,0x00,
0x05,0x4A,0x00,0x00,0x05,0x00,0x00,0x05,0x40
},
{
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xEA,0x00,
0x02,0xEA,0x00,0x02,0xEA,0x00,0x02,0xEA,0x00,
0x00,0xA8,0x50,0x00,0x15,0x50,0x00,0xAA,0x50,
0x20,0xAA,0x50,0x2A,0xAA,0x50,0x0A,0xAA,0x50,
0x00,0xAA,0x50,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0xAA,0x00,0x0A,0xA2,0x80,0x0A,0xA2,0x94,
0x0A,0x02,0x94,0x15,0x00,0x94,0x15,0x00,0x04
},
{
0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0xBF,0x80,
0x00,0xAE,0x80,0x00,0xAE,0x80,0x00,0xAE,0x80,
0x00,0x2A,0x00,0x00,0x15,0x02,0x20,0xAA,0xAA,
0x2A,0xBF,0xA8,0x0A,0xAA,0xA0,0x02,0xBF,0x80,
0x00,0xAA,0x80,0x00,0xFF,0xC0,0x00,0xAA,0x80,
0x00,0xAA,0x80,0x02,0xA2,0xA0,0x02,0x80,0xA0,
0x02,0x80,0xA0,0x01,0x40,0x50,0x05,0x40,0x54
},
{
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xEA,0x00,
0x02,0xEA,0x00,0x02,0xEA,0x00,0x02,0xEA,0x00,
0x00,0xA8,0x50,0x00,0x15,0x50,0x00,0xAA,0x50,
0x08,0xAA,0x90,0x0A,0xAA,0xA0,0x02,0xAA,0x60,
0x00,0xAA,0x50,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0xA2,0x00,0x00,0xA8,0x80,0x00,0x2A,0x80,
0x02,0x8A,0x90,0x01,0x40,0x50,0x05,0x41,0x40
},
// right direction
{
0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0xAB,0x80,
0x00,0xAB,0x80,0x00,0xAB,0x80,0x00,0xAB,0x80,
0x05,0x2A,0x00,0x05,0x54,0x00,0x05,0xAA,0x00,
0x05,0xAA,0x00,0x05,0xAA,0x00,0x05,0xAA,0xA0,
0x05,0xAA,0x80,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0xAA,0x00,0x02,0x8A,0x00,0x02,0x8A,0x00,
0x02,0x88,0x00,0x01,0x45,0x40,0x01,0x45,0x40
},
{
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xAA,0x00,
0x02,0xAA,0x00,0x02,0xAA,0x20,0x02,0xAA,0x20,
0x00,0xA8,0x20,0x00,0x54,0xA0,0x0A,0x56,0xA0,
0x2A,0x56,0x80,0x2A,0x56,0x00,0x22,0x56,0x00,
0x22,0x56,0x00,0x23,0xFF,0x00,0x02,0xAA,0x00,
0x02,0x8A,0x00,0x02,0x8A,0x00,0x02,0x85,0x00,
0x02,0x85,0x40,0x01,0x40,0x00,0x05,0x40,0x00
},
{
0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0xAB,0x80,
0x00,0xAB,0x80,0x00,0xAB,0x80,0x00,0xAB,0x80,
0x05,0x2A,0x00,0x05,0x54,0x00,0x05,0xAA,0x00,
0x05,0xAA,0x08,0x05,0xAA,0xA8,0x05,0xAA,0xA0,
0x05,0xAA,0x00,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0xAA,0x00,0x02,0x8A,0xA0,0x16,0x8A,0xA0,
0x16,0x80,0xA0,0x16,0x00,0x54,0x10,0x00,0x54
},
{
0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0xBF,0x80,
0x00,0xAE,0x80,0x00,0xAE,0x80,0x00,0xAE,0x80,
0x00,0x2A,0x00,0x20,0x15,0x00,0x2A,0xAA,0x82,
0x0A,0xBF,0xAA,0x02,0xAA,0xA8,0x00,0xBF,0xA0,
0x00,0xAA,0x80,0x00,0xFF,0xC0,0x00,0xAA,0x80,
0x00,0xAA,0x80,0x02,0xA2,0xA0,0x02,0x80,0xA0,
0x02,0x80,0xA0,0x01,0x40,0x50,0x05,0x40,0x54
},
{
0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0xAB,0x80,
0x00,0xAB,0x80,0x00,0xAB,0x80,0x00,0xAB,0x80,
0x05,0x2A,0x00,0x05,0x54,0x00,0x05,0xAA,0x00,
0x06,0xAA,0x20,0x0A,0xAA,0xA0,0x09,0xAA,0x80,
0x05,0xAA,0x00,0x00,0xFF,0x00,0x00,0xAA,0x00,
0x00,0x8A,0x00,0x02,0x2A,0x00,0x02,0xA8,0x00,
0x06,0xA2,0x80,0x05,0x01,0x40,0x01,0x41,0x50
},
// explosion
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,
0x00,0x20,0x00,0x08,0x20,0x80,0x02,0x02,0x00,
0x00,0x10,0x00,0x00,0x54,0x00,0x00,0x10,0x00,
0x02,0x02,0x00,0x08,0x20,0x80,0x00,0x20,0x00,
0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0x02,0x00,
0x08,0x00,0x80,0x20,0x00,0x20,0x20,0x54,0x20,
0x21,0x01,0x20,0x21,0x01,0x20,0x21,0x01,0x20,
0x20,0x54,0x20,0x20,0x00,0xA0,0x08,0x00,0x80,
0x02,0x02,0x00,0x00,0xA8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0x02,0x00,
0x08,0x10,0x80,0x08,0x54,0x80,0x08,0x10,0x80,
0x02,0x02,0x00,0x00,0xA8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
};
typedef enum {
STANDING, JUMPING, CLIMBING
} ActorState;
typedef struct Actor {
word xx;
word yy;
sbyte xvel;
sbyte yvel;
ActorState state;
bool faceleft;
} Actor;
Actor actors[MAX_ACTORS];
Actor* player = &actors[0];
void draw_actor(register Actor* actor) {
word xpos = actor->xx;
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();
}
}

View File

@ -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

131
presets/c64/joygame.c Normal file
View File

@ -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<NUM_SPRITES; i++) {
sprite_shape(SPRITE_SHAPE+i, SPRITE_MC_DATA+64*i);
}
}
void init_sprite_positions(void) {
byte i;
// setup sprite positions
player_x = 172;
player_y = 145;
// set random positions for non-players
// and draw them to sprite shadow buffer
srand(7);
for (i=1; i<8; i++) {
int x = rand() % (320 - 24) + 24;
byte y = rand() % (229 - 50) + 50;
sprite_draw(i, x, y, SPRITE_SHAPE + 2);
sprshad.spr_color[i] = i | 8;
}
}
void move_player(byte joy) {
// move sprite based on joystick
if (JOY_LEFT(joy)) { player_x -= 1; faceleft = 1; } // move left 1 pixel
if (JOY_RIGHT(joy)) { player_x += 1; faceleft = 0; } // move right 1 pixel
if (JOY_UP(joy)) { player_y -= 1; } // move up 1 pixel
if (JOY_DOWN(joy)) { player_y += 1; } // move down 1 pixel
// draw player into sprite shadow buffer
sprite_draw(0, player_x, player_y, SPRITE_SHAPE + faceleft);
}
void move_non_players(void) {
byte i;
// wiggle non-player sprites randomly
for (i=1; i<8; i++) {
sprshad.spr_pos[i].y += rand() & i;
}
}
void main(void) {
// variables
byte bgcoll; // sprite background collision flags
byte sprcoll; // sprite collision flags
byte joy; // joystick flags
clrscr();
// install the joystick driver
joy_install (joy_static_stddrv);
// set multicolor sprites and colors
sprshad.spr_mcolor = 0b11111111;
sprshad.spr_color[0] = SPRITE_MC_DATA[63];
VIC.spr_mcolor0 = COLOR_GRAY2;
VIC.spr_mcolor1 = COLOR_BLACK;
// setup sprites
init_sprite_shapes();
init_sprite_positions();
// loop forever
while (1) {
// wait for end of frame
waitvsync();
// update sprite registers from sprite shadow
// buffer before frame starts drawing
sprite_update(DEFAULT_SCREEN);
// get joystick bits
joy = joy_read(0);
move_player(joy);
// move other objects
move_non_players();
// grab and reset collision flags
sprcoll = VIC.spr_coll;
bgcoll = VIC.spr_bg_coll;
// change color when player collides with sprite
sprshad.spr_color[0] = (sprcoll & 1) ? 10 : 3;
}
}

View File

@ -13,18 +13,6 @@ const char SPRITE_DATA[64] = {
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) {
// variables
int x = 172; // sprite X position (16-bit)
@ -32,33 +20,40 @@ void main(void) {
char bgcoll; // sprite background collision flags
char joy; // joystick flags
// install the joystick driver
joy_install (joy_static_stddrv);
// 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);
POKE(0x400 + 0x3f8 + 0, 0x3800 / 64);
// set position and color
VIC.spr_pos[0].x = 172;
VIC.spr_pos[0].y = 145;
VIC.spr_color[0] = COLOR_GREEN;
// enable sprite #0
VIC.spr_ena = 0b00000001;
// install the joystick driver
joy_install (joy_static_stddrv);
// loop forever
while (1) {
// get joystick bits
joy = joy_read(0);
// move sprite based on joystick
if (JOY_LEFT(joy)) --x;
if (JOY_UP(joy)) --y;
if (JOY_RIGHT(joy)) ++x;
if (JOY_DOWN(joy)) ++y;
if (JOY_LEFT(joy)) { x -= 1; } // move left 1 pixel
if (JOY_RIGHT(joy)) { x += 1; } // move right 1 pixel
if (JOY_UP(joy)) { y -= 1; } // move up 1 pixel
if (JOY_DOWN(joy)) { y += 1; } // move down 1 pixel
// wait for end of frame
waitvsync();
// set sprite registers based on position
VIC.spr0_x = x;
VIC.spr0_y = y;
VIC.spr_hi_x = (x & 256) ? 1 : 0; // set X hi bit?
VIC.spr_pos[0].x = x;
VIC.spr_pos[0].y = y;
// set X coordinate high bit
VIC.spr_hi_x = (x & 0x100) ? 1 : 0;
// grab and reset collision flags
bgcoll = VIC.spr_bg_coll;
// change color when we collide with background
VIC.spr0_color = (bgcoll & 1) ? 10 : 3;
// wait for end of frame
waitvsync();
VIC.spr_color[0] = (bgcoll & 1) ?
COLOR_LIGHTRED : COLOR_CYAN;
}
}

View File

@ -12,18 +12,17 @@
#include "common.h"
//#link "multilines.c"
void setup_bitmap_multi();
void set_pixel(byte x, byte y, byte color);
//#link "mcbitmap.c"
#include "mcbitmap.h"
/* Graphics definitions */
#define SCREEN_X 160
#define SCREEN_Y 192
#define MAXCOL 16
#define maxiterations 16
#define maxiterations 64
#define fpshift (10)
#define fpone (1<<fpshift)
#define tofp(_x) ((_x)<<fpshift)
#define fromfp(_x) ((_x)>>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;
}

View File

@ -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;

15
presets/c64/mcbitmap.h Normal file
View File

@ -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);

View File

@ -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

View File

@ -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) \

View File

@ -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

View File

@ -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");

View File

@ -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 <cbm_petscii_charmap.h>
#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<SCROLL_ROWS; row++) {
POKE(addr, get_char_for_row(row));
addr += 40;
}
}
void scroll_one_column_left() {
// copy several rows of screen memory
// backwards one byte
const word start = SCRNADR(0x400, 0, SCROLL_TOP);
const word nbytes = SCROLL_ROWS*40-1;
memcpy((byte*)start, (byte*)start+1, nbytes);
// draw the right column of characters
draw_right_column();
}
void scroll_one_pixel_left() {
// scroll left one pixel
scroll_x -= 1;
// set scroll register with lower three bits
VIC.ctrl2 = (VIC.ctrl2 & ~0b111) | (scroll_x & 0b111);
// move screen memory if the scroll register
// has just gone past 0 and wrapped to 7
if ((scroll_x & 0b111) == 0b111) {
scroll_one_column_left();
}
}
void main(void) {
clrscr();
printf("\r\n Hello World!");
printf("\r\n\r\n This is how we scroll");
printf("\r\n\r\n One line at a time");
printf("\r\n\r\n But we don't have time");
printf("\r\n\r\n To copy all the bytes ");
printf("\n Hello Scrolling World!");
printf("\n\n We change scroll registers");
printf("\n\n And move screen memory");
printf("\n\n But we don't have time");
printf("\n\n To copy all 25 rows ");
printf("\n\n In a single frame ");
VIC.ctrl1 = 0x10; // 24 lines
VIC.ctrl2 = 0x00; // 38 columns
// get screen buffer address
scrnbuf = (byte*)((VIC.addr << 6) & 0x3c00);
VIC.bordercolor = COLOR_GRAY1;
// infinite loop
while (1) {
x--;
// set scroll registers
VIC.ctrl1 = VIC.ctrl1 & 0xf8;
VIC.ctrl1 |= (y & 7);
VIC.ctrl2 = VIC.ctrl2 & 0xf8;
VIC.ctrl2 |= (x & 7);
// wait for vsync
waitvsync();
// every 8 pixels, move screen cells
if ((x & 7) == 0) {
memcpy(scrnbuf, scrnbuf+1, 40*8-1);
}
// scroll one pixel to the left
// and move screen memory every 8 pixels
scroll_one_pixel_left();
}
}

View File

@ -2,49 +2,57 @@
#include "common.h"
//#link "common.c"
byte x = 0; // x scroll position
byte y = 0; // y scroll position
byte* scrnbuf[2]; // screen buffer(s)
byte frame = 0;
#include <cbm_petscii_charmap.h>
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();
}
}

View File

@ -2,44 +2,44 @@
#include "common.h"
//#link "common.c"
#include <cbm_petscii_charmap.h>
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);

View File

@ -8,6 +8,8 @@
#include "sprites.h"
//#link "sprites.c"
#include <cbm_petscii_charmap.h>
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

View File

@ -8,6 +8,8 @@
#include "sprites.h"
//#link "sprites.c"
#include <cbm_petscii_charmap.h>
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

View File

@ -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

View File

@ -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);

View File

@ -2,6 +2,8 @@
#include "common.h"
//#link "common.c"
#include <tgi.h>
//#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();
}

341
presets/c64/side_scroller.c Normal file
View File

@ -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<SCROLL_ROWS; row++) {
POKE(addr, get_char_for_row(row));
addr += 40;
}
}
void scroll_one_column_left() {
// copy several rows of screen memory
// backwards one byte
const word start = SCRNADR(GAME_BASE, 0, SCROLL_TOP);
const word nbytes = SCROLL_ROWS*40-1;
memcpy((byte*)start, (byte*)start+1, nbytes);
// draw the right column of characters
draw_right_column();
}
void scroll_one_pixel_left() {
// scroll left one pixel
scroll_x -= 1;
// set scroll register with lower three bits
VIC.ctrl2 = (VIC.ctrl2 & ~7) | (scroll_x & 7);
// move screen memory if the scroll register
// has just gone past 0 and wrapped to 7
if ((scroll_x & 7) == 7) {
scroll_one_column_left();
}
}
void detect_player_collision(byte bgcoll, byte sprcoll) {
// did we hit a powerup? (#0 and #1)
bool hit_powerup = (sprcoll & 0b011) == 0b011;
// did player and obstacle sprite (#0 and #2) collide?
bool hit_obstacle = (sprcoll & 0b101) == 0b101;
// did player (#0) collide with background?
hit_obstacle |= (bgcoll & 0b001) != 0;
// did we hit anything bad?
if (hit_obstacle) {
// make player fall downward and backward
player_vel_y = -JUMP_VELOCITY;
player_x -= 1;
sprshad.spr_color[PLAYER_INDEX] = COLOR_LIGHTRED;
PLAY_TONE(500);
if (score != 0) { add_score(0x9999); } // BCD -1
update_scoreboard();
} else {
sprshad.spr_color[PLAYER_INDEX] = COLOR_GREEN;
}
// did we hit powerup?
if (hit_powerup) {
sprshad.spr_color[POWERUP_INDEX] += 1; // cycle colors
PLAY_TONE(8000);
add_score(1);
update_scoreboard();
}
}
void main() {
// clear screen, set background color
clrscr();
VIC.bgcolor[0] = COLOR_CYAN;
VIC.bordercolor = COLOR_BLUE;
// set vertical scroll = 3, 25 rows
VIC.ctrl1 = 0b00011011;
// set 38 column mode (for X scrolling)
VIC.ctrl2 = 0b00000000;
// set uniform color of characters
memset(COLOR_RAM, COLOR_WHITE, 1000);
// install the joystick driver
joy_install (joy_static_stddrv);
// setup sound
SID_INIT(8,0);
// set multicolor sprites and colors in shadow buffer
sprite_clear(); // clear shadow buffer
sprshad.spr_mcolor = 0b11111111; // all sprites multicolor
sprshad.spr_exp_y = 1; // double height
// set colors
sprshad.spr_color[PLAYER_INDEX] = COLOR_GREEN;
VIC.spr_mcolor0 = COLOR_GRAY2;
VIC.spr_mcolor1 = COLOR_BLACK;
// setup sprites
init_sprite_shapes();
init_sprite_positions();
// setup scoreboard
init_scoreboard();
// setup rasterirq library for scoreboard split
DLIST_SETUP(display_list);
// game loop, repeat forever
while (1) {
// saved collision flags
byte sprcoll, bgcoll;
// wait for end of frame
waitvsync();
//--- START TIME CRITICAL SECTION
// grab and reset collision flags
sprcoll = VIC.spr_coll;
bgcoll = VIC.spr_bg_coll;
// update sprite registers from sprite shadow buffer
sprite_update(DEFAULT_SCREEN);
// scroll screen
scroll_one_pixel_left();
//--- END TIME CRITICAL SECTION
// use collision flags to see if player collided
detect_player_collision(bgcoll, sprcoll);
// get joystick bits and move player
move_player(joy_read(0));
// move obstacle and powerup sprites
move_items();
}
}

55
presets/c64/sidmacros.h Normal file
View File

@ -0,0 +1,55 @@
// SID voices are v1, v2, v3
// wave options flags
#define SID_GATE 0x01
#define SID_SYNC 0x02
#define SID_RINGMOD 0x04
#define SID_TESTBIT 0x08
#define SID_TRIANGLE 0x10
#define SID_SAWTOOTH 0x20
#define SID_SQUARE 0x40
#define SID_NOISE 0x80
// Init SID global volume
// volume: 0-15
// filters: bitmask
#define SID_INIT(volume, filters) \
SID.amp = (volume) | ((filters)<<4);
// stop voice
#define SID_STOP(voice) \
SID.voice.ctrl &= ~SID_GATE;
// start voice
#define SID_START(voice) \
SID.voice.ctrl |= SID_GATE;
// set ADSR envelope
#define SID_ADSR(voice,attack,decay,sustain,release) \
SID.voice.ad = ((decay)&15) | ((attack)<<4); \
SID.voice.sr = ((release)&15) | ((sustain)<<4);
// set frequency (0 - 65535)
#define SID_FREQ(voice,_freq) \
SID.voice.freq = (_freq);
// set pulse width (0 - 4095)
#define SID_PULSEWIDTH(voice,_pw) \
SID.voice.pw = (_pw);
// set wave shape and options
#define SID_WAVE(voice,options) \
SID.voice.ctrl = (SID.voice.ctrl & 1) | (options)
// play a quick square wave pulse
#define SID_PULSE_DECAY(voice, period) \
SID_STOP(voice) \
SID_FREQ(voice,period); \
SID_PULSEWIDTH(voice,0x200); \
SID_ADSR(voice,8,8,0,4); \
SID_WAVE(voice,SID_SQUARE|SID_GATE); \
// play a tone if one is not already playing
#define PLAY_TONE(period) \
if (!SID.read3) { SID_PULSE_DECAY(v3, (period)) }

View File

@ -37,6 +37,7 @@ _sid_start:
bne skipstop
_sid_stop:
lda #$00
sta $d418
skipstop:
sta _sid_playing
rts

View File

@ -7,6 +7,9 @@
#include <c64.h>
#include <cbm_petscii_charmap.h>
#include "common.h"
//#link "common.c"
void main(void) {
clrscr();
printf("\nHello World!\n");

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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] = {

View File

@ -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

View File

@ -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! ");
}
}

View File

@ -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; i<SPRITES_PER_ROW; i++) {
sprite_draw(i, i*50+50, row*50+60, SPRITE_SHAPE);
sprshad.spr_color[i] = (i+row)|8;
}
// allocate sprite buffer for row
sprite_rows[row] = (SpriteShadow*) malloc(sizeof(SpriteShadow));
// and copy local buffer into it
*sprite_rows[row] = sprshad;
}
}
void draw_sprite_row(byte row, byte rasterline) {
// copy sprite row data to sprite shadow buffer
sprshad = *sprite_rows[row];
// player is part of row 2, draw player?
if (row == 2) {
sprite_draw(7, player_x, player_y, SPRITE_SHAPE+1);
sprshad.spr_color[7] = 15;
}
// wait for the raster line
raster_wait(rasterline);
// then update sprite registers from shadow buffer
VIC.bordercolor = row+1; // (so we see the timing)
sprite_update(DEFAULT_SCREEN);
VIC.bordercolor = 0;
}
void move_sprite_x(SpriteShadow* spr,
byte index,
sbyte delta_x)
{
word x = spr->spr_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<SPRITES_PER_ROW; i++) {
move_sprite_x(sprite_rows[0], i, 3);
move_sprite_x(sprite_rows[1], i, -2);
}
}
void move_player() {
byte joy = PEEK(0xdc01); // read joystick #0
if (joy & 0x8) { player_x -= 1; } // left
if (joy & 0x4) { player_x += 1; } // right
}
void iterate_game(void) {
waitvsync();
draw_sprite_row(0, 1);
draw_sprite_row(1, 60+21);
draw_sprite_row(2, 110+21);
move_sprites();
move_player();
VIC.bordercolor = 9;
}
void main(void) {
VIC.bordercolor = 0;
clrscr();
// setup sprite library and copy sprite to VIC bank
sprite_clear();
sprite_set_shapes(SPRITEMC, SPRITE_SHAPE, NUM_SPRITE_PATTERNS);
// set colors
VIC.spr_mcolor0 = 4;
VIC.spr_mcolor1 = 7;
// set sprite initial positions
init_sprites();
// turn off interrupts so we don't mess up timing
asm("sei");
// game loop
while (1) {
iterate_game();
}
}

View File

@ -0,0 +1,149 @@
#include "common.h"
//#link "common.c"
//#link "multisprite.ca65"
#include "rasterirq.h"
//#link "rasterirq.ca65"
#define NUM_TEST_SPRITES 24
byte* sprite_bank = (byte*)DEFAULT_SCREEN + 0x3f8;
/*{w:12,h:21,bpp:2,brev:1}*/
const char SPRITEMC[3*21] = {
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
};
/*
const byte BITS[8] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
};
const byte NOTBITS[8] = {
~0x01, ~0x02, ~0x04, ~0x08, ~0x10, ~0x20, ~0x40, ~0x80
};
typedef struct MSpriteFlags {
byte xhi:1;
byte exp_x:1;
byte exp_y:1;
byte mcolor:1;
byte bgprio:1;
} MSpriteFlags;
*/
#include "multisprite.h"
void sprite_shape(char* vicbank, byte index, const char* sprite_data) {
memmove(vicbank + index*64, sprite_data, 64);
}
void setup_sprites() {
byte i;
sprite_shape((void*)0x0, 255, SPRITEMC);
for (i=0; i<MAX_MSPRITES; i++) {
msprite_order[i] = i;
msprite_y[i] = 255;
}
for (i=0; i<NUM_TEST_SPRITES; i++) {
int x = i*13+20;
msprite_x_lo[i] = x;
msprite_x_hi[i] = x>>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<NUM_TEST_SPRITES; i++) {
int xvel = msprite_xvel_lo[i] + msprite_xvel_hi[i]*256;
int yvel = msprite_yvel_lo[i] + msprite_yvel_hi[i]*256;
int xpos = msprite_x_lo[i] + msprite_x_hi[i]*256;
int ypos = msprite_y[i];
xpos -= 172;
ypos -= 145;
xvel -= xpos / 8;
yvel -= ypos / 8;
msprite_xvel_lo[i] = xvel;
msprite_xvel_hi[i] = xvel >> 8;
msprite_yvel_lo[i] = yvel;
msprite_yvel_hi[i] = yvel >> 8;
}
}
void do_test() {
byte i;
raster_wait(160);
for (i=0; i<NUM_TEST_SPRITES; i++) {
msprite_yvel_lo[i] = i*8;
//msprite_add_position(i,i&3,i&3);
}
}
void main() {
clrscr();
setup_sprites();
// set colors
VIC.spr_mcolor = 0xff;
VIC.spr_mcolor0 = 4;
VIC.spr_mcolor1 = 7;
DLIST_SETUP(display_list);
while (1) {
do_test();
}
}

View File

@ -893,21 +893,19 @@ export abstract class BaseMachinePlatform<T extends Machine> 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();
}

View File

@ -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';

View File

@ -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);
}
/*

View File

@ -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() {

View File

@ -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:[

View File

@ -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) {