c64: presets, new vsync
This commit is contained in:
parent
340ef9a4bc
commit
472b9f952d
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
|
@ -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
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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)) }
|
|
@ -37,6 +37,7 @@ _sid_start:
|
|||
bne skipstop
|
||||
_sid_stop:
|
||||
lda #$00
|
||||
sta $d418
|
||||
skipstop:
|
||||
sta _sid_playing
|
||||
rts
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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] = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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! ");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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:[
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue