mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-07 17:29:31 +00:00
Merge branch
This commit is contained in:
commit
a86e554336
|
@ -292,9 +292,9 @@ div.emuspacer {
|
|||
padding: 20px;
|
||||
background: #000;
|
||||
margin-top:40px;
|
||||
margin-left:5%;
|
||||
margin-right:5%;
|
||||
width:90%;
|
||||
margin-left:3%;
|
||||
margin-right:3%;
|
||||
width:94%;
|
||||
pointer-events:auto;
|
||||
}
|
||||
.emuvideo:focus {
|
||||
|
|
80
presets/c64/23matches.c
Normal file
80
presets/c64/23matches.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
|
||||
#include "common.h"
|
||||
#include <cbm_petscii_charmap.h>
|
||||
|
||||
int matches; // number of matches remaining
|
||||
int take; // # of matches to take on this turn
|
||||
|
||||
void print_matches() {
|
||||
printf("\nThere are %d matches left.\n", matches);
|
||||
}
|
||||
|
||||
void human_moves() {
|
||||
print_matches();
|
||||
// loop until we get a valid move
|
||||
while (1) {
|
||||
printf("\n>> Your turn. Take 1, 2, or 3 matches?");
|
||||
// did we get exactly one input value?
|
||||
if (scanf("%d", &take) == 1) {
|
||||
// is it between 1 and 3?
|
||||
if (take >= 1 && take <= 3) {
|
||||
// are there not enough matches?
|
||||
if (take > matches) {
|
||||
printf("Not enough matches! Try again.\n");
|
||||
continue; // go back to start of loop
|
||||
} else {
|
||||
// take the appropriate number of matches
|
||||
printf("You took %d matches.\n", take);
|
||||
matches -= take;
|
||||
break; // break out of loop
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Bad input! Type a number from 1 to 3.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void computer_moves() {
|
||||
print_matches();
|
||||
// simple AI: hard coded if 1-4 matches left
|
||||
// otherwise take random number from 1 to 3
|
||||
switch (matches) {
|
||||
case 1: take = 1; break;
|
||||
case 2: take = 1; break;
|
||||
case 3: take = 2; break;
|
||||
case 4: take = 3; break;
|
||||
default: take = (rand() % 3) + 1; break;
|
||||
}
|
||||
printf("\n<< My turn. I'll take %d matches.\n", take);
|
||||
matches -= take;
|
||||
}
|
||||
|
||||
void play_game(void) {
|
||||
printf(
|
||||
"When it is your turn, you may take\n"
|
||||
"1, 2 or 3 matches. I will do the same.\n\n"
|
||||
"Whoever takes the last match loses.\n");
|
||||
|
||||
matches = 23;
|
||||
// loop until no more matches
|
||||
while (matches > 0) {
|
||||
// move human, check if they lost
|
||||
human_moves();
|
||||
if (matches == 0) {
|
||||
printf("You lose, turkey!\nBetter luck next time.\n");
|
||||
break;
|
||||
}
|
||||
// move computer, check if they lost
|
||||
computer_moves();
|
||||
if (matches == 0) {
|
||||
printf("I lost! You must be good!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
clrscr();
|
||||
printf("*** 23 MATCHES ***\n\n");
|
||||
play_game();
|
||||
}
|
BIN
presets/c64/badspacerobots-c64.multi.bin
Normal file
BIN
presets/c64/badspacerobots-c64.multi.bin
Normal file
Binary file not shown.
|
@ -5,6 +5,6 @@
|
|||
.org $0801 ; start of BASIC program
|
||||
|
||||
.word BASIC_END, 10 ; Next line and current line number
|
||||
.byte $9e," 2064",0 ; SYS 2064
|
||||
.byte $9e," 2062",0 ; SYS 2062
|
||||
BASIC_END:
|
||||
.word 0 ; End of program
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
49
presets/c64/c64-sid.cfg
Normal file
49
presets/c64/c64-sid.cfg
Normal file
|
@ -0,0 +1,49 @@
|
|||
FEATURES {
|
||||
STARTADDRESS: default = $0801;
|
||||
}
|
||||
SYMBOLS {
|
||||
__LOADADDR__: type = import;
|
||||
__EXEHDR__: type = import;
|
||||
__STACKSIZE__: type = weak, value = $0800; # 2k stack
|
||||
__HIMEM__: type = weak, value = $8000;
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", define = yes, start = $0002, size = $001A;
|
||||
LOADADDR: file = %O, start = %S - 2, size = $0002;
|
||||
HEADER: file = %O, define = yes, start = %S, size = $000D;
|
||||
LOWMAIN: file = %O, define = yes, start = __HEADER_LAST__, size = $1000 - __HEADER_LAST__, fill = yes;
|
||||
SIDFILE: file = %O, define = yes, start = $1000, size = $1000, fill = yes;
|
||||
MAIN: file = %O, define = yes, start = $2000, size = __HIMEM__ - $2000;
|
||||
BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __STACKSIZE__ - __ONCE_RUN__;
|
||||
VICBANK: file = %O, start = $8000, size = $4000;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
LOADADDR: load = LOADADDR, type = ro;
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
STARTUP: load = LOWMAIN, type = ro;
|
||||
LOWCODE: load = LOWMAIN, type = ro, optional = yes;
|
||||
SIDFILE: load = SIDFILE, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
INIT: load = MAIN, type = rw;
|
||||
ONCE: load = MAIN, type = ro, define = yes;
|
||||
BSS: load = BSS, type = bss, define = yes;
|
||||
VICBANK: load = MAIN, type = ro, optional = yes;
|
||||
}
|
||||
FEATURES {
|
||||
CONDES: type = constructor,
|
||||
label = __CONSTRUCTOR_TABLE__,
|
||||
count = __CONSTRUCTOR_COUNT__,
|
||||
segment = ONCE;
|
||||
CONDES: type = destructor,
|
||||
label = __DESTRUCTOR_TABLE__,
|
||||
count = __DESTRUCTOR_COUNT__,
|
||||
segment = RODATA;
|
||||
CONDES: type = interruptor,
|
||||
label = __INTERRUPTOR_TABLE__,
|
||||
count = __INTERRUPTOR_COUNT__,
|
||||
segment = RODATA,
|
||||
import = __CALLIRQ__;
|
||||
}
|
|
@ -1,24 +1,31 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <c64.h>
|
||||
#include <joystick.h>
|
||||
|
||||
#include "bcd.h"
|
||||
//#link "bcd.c"
|
||||
//#resource "c64-sid.cfg"
|
||||
#define CFGFILE c64-sid.cfg
|
||||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "sidplaysfx.h"
|
||||
//#resource "sidmusic1.bin"
|
||||
//#link "sidplaysfx.ca65"
|
||||
|
||||
#include "rasterirq.h"
|
||||
//#link "rasterirq.ca65"
|
||||
|
||||
#include "bcd.h"
|
||||
//#link "bcd.c"
|
||||
|
||||
#include "scrolling.h"
|
||||
//#link "scrolling.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
// indices of sound effects (0..3)
|
||||
typedef enum { SND_START, SND_HIT, SND_COIN, SND_JUMP } SFXIndex;
|
||||
// indices of sound effects
|
||||
#define SND_JUMP 0
|
||||
#define SND_HIT 2
|
||||
#define SND_COIN 1
|
||||
#define SND_FALL 3
|
||||
|
||||
///// DEFINES
|
||||
|
||||
|
@ -62,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,
|
||||
|
@ -372,8 +379,9 @@ void refresh_floor(byte floor) {
|
|||
|
||||
byte explode_timer = 0;
|
||||
|
||||
#define SPRITE_SHAPE_FIRST 192
|
||||
#define SPRITE_XPLODE 7
|
||||
#define SHAPE_XPLODE0 (32+10)
|
||||
#define SHAPE_XPLODE0 (SPRITE_SHAPE_FIRST+10)
|
||||
#define NUM_XPLODE_SHAPES 3
|
||||
|
||||
void explode(int x, byte y) {
|
||||
|
@ -446,7 +454,7 @@ void draw_actor(byte i) {
|
|||
a->onscreen = 0;
|
||||
return; // offscreen vertically
|
||||
}
|
||||
name = 32 + (a->state - WALKING);
|
||||
name = SPRITE_SHAPE_FIRST + (a->state - WALKING);
|
||||
switch (a->state) {
|
||||
case INACTIVE:
|
||||
a->onscreen = 0;
|
||||
|
@ -469,7 +477,7 @@ void draw_actor(byte i) {
|
|||
void refresh_actors() {
|
||||
byte i;
|
||||
yscroll = BOTTOM_Y + scroll_fine_y + (START_ORIGIN_Y - origin_y)*8;
|
||||
sprite_clear();
|
||||
sprshad.spr_ena = 0; // make all sprites invisible
|
||||
for (i=0; i<MAX_ACTORS; i++)
|
||||
draw_actor(i);
|
||||
animate_explosion();
|
||||
|
@ -541,6 +549,7 @@ void move_actor(struct Actor* actor, byte joystick, bool scroll) {
|
|||
actor->yvel = 15;
|
||||
if (joystick & JOY_LEFT_MASK) actor->xvel = -1;
|
||||
if (joystick & JOY_RIGHT_MASK) actor->xvel = 1;
|
||||
if (scroll) sid_sfx(SND_JUMP);
|
||||
} else if (joystick & JOY_LEFT_MASK) {
|
||||
actor->x--;
|
||||
actor->dir = 1;
|
||||
|
@ -605,6 +614,7 @@ void move_actor(struct Actor* actor, byte joystick, bool scroll) {
|
|||
if (actor->state == WALKING &&
|
||||
is_in_gap(actor->x, floors[actor->level].gap)) {
|
||||
fall_down(actor);
|
||||
if (scroll) sid_sfx(SND_FALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -626,11 +636,11 @@ void pickup_object(Actor* actor) {
|
|||
if (objtype == ITEM_MINE) {
|
||||
// we hit a mine, fall down
|
||||
fall_down(actor);
|
||||
//sfx_play(SND_HIT,0);
|
||||
sid_sfx(SND_HIT);
|
||||
} else {
|
||||
// we picked up an object, add to score
|
||||
//score = bcd_add(score, 1);
|
||||
//sfx_play(SND_COIN,0);
|
||||
sid_sfx(SND_COIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -717,6 +727,9 @@ void play_scene() {
|
|||
create_actors_on_floor(2);
|
||||
refresh_screen();
|
||||
|
||||
sid_init(1);
|
||||
sid_start();
|
||||
|
||||
while (actors[0].level != MAX_FLOORS-1) {
|
||||
refresh_actors();
|
||||
move_player();
|
||||
|
@ -728,6 +741,7 @@ void play_scene() {
|
|||
if (VIC.spr_coll & 0x01) {
|
||||
if (actors[0].level > 0 && check_collision(&actors[0])) {
|
||||
fall_down(&actors[0]);
|
||||
sid_sfx(SND_HIT);
|
||||
}
|
||||
}
|
||||
if (swap_needed) sprite_update(hidbuf);
|
||||
|
@ -739,26 +753,34 @@ void play_scene() {
|
|||
blimp_pickup_scene();
|
||||
}
|
||||
|
||||
// main display list
|
||||
void game_displaylist(void) {
|
||||
// VIC.bordercolor = 2;
|
||||
sid_update();
|
||||
// VIC.bordercolor = 0;
|
||||
// DLIST_NEXT(42);
|
||||
// VIC.bordercolor = 3;
|
||||
DLIST_RESTART(20);
|
||||
}
|
||||
|
||||
// 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(hidbuf, 32+i, SPRITE_DATA[i]);
|
||||
}
|
||||
sprite_set_shapes(SPRITE_DATA, SPRITE_SHAPE_FIRST, NUM_SPRITE_PATTERNS);
|
||||
sprshad.spr_mcolor = 0xff;
|
||||
sprshad.spr_mcolor0 = 0x0f;
|
||||
sprshad.spr_mcolor1 = 0x00;
|
||||
VIC.spr_mcolor0 = 0x0f;
|
||||
VIC.spr_mcolor1 = 0x00;
|
||||
// select character set 2
|
||||
VIC.addr = 0x15;
|
||||
// start scrolling @ bottom of level
|
||||
origin_y = START_ORIGIN_Y;
|
||||
// install joystick
|
||||
joy_install (joy_static_stddrv);
|
||||
// setup display list
|
||||
DLIST_SETUP(game_displaylist);
|
||||
// main game loop
|
||||
while (1) {
|
||||
make_floors();
|
||||
|
|
|
@ -1,10 +1,28 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
void raster_wait(unsigned char line) {
|
||||
void raster_wait(byte line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
}
|
||||
|
||||
void wait_vblank(void) {
|
||||
raster_wait(255);
|
||||
}
|
||||
|
||||
static byte VIC_BANK_PAGE[4] = {
|
||||
0xc0, 0x80, 0x40, 0x00
|
||||
};
|
||||
|
||||
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__;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,80 @@
|
|||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <c64.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <peekpoke.h>
|
||||
#include <string.h>
|
||||
#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
|
||||
|
||||
void raster_wait(unsigned char line);
|
||||
void wait_vblank(void);
|
||||
|
||||
///// 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_BITMAP(_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);
|
||||
|
||||
// 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
|
||||
|
|
638
presets/c64/fullscrollgame.c
Normal file
638
presets/c64/fullscrollgame.c
Normal file
|
@ -0,0 +1,638 @@
|
|||
|
||||
#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
|
||||
|
||||
|
||||
// level map data
|
||||
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_data[];
|
||||
|
||||
|
||||
static byte framecount;
|
||||
static byte framemask;
|
||||
|
||||
const byte BITMASKS[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
|
||||
|
||||
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_data[col + row * MAP_ROWS];
|
||||
tilechar = chartileset_data[xofs + (yofs + tileindex*4)*4];
|
||||
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* const player = &actors[0];
|
||||
|
||||
void draw_actor(register Actor* actor, byte index) {
|
||||
byte shape = 240;
|
||||
word xpos = actor->xx + pixofs_x + fine_correct_x + ACTOR_OFFSET_X;
|
||||
word ypos = actor->yy + pixofs_y + fine_correct_y + ACTOR_OFFSET_Y;
|
||||
if (xpos > 320 || ypos > 250) {
|
||||
ypos = 255;
|
||||
}
|
||||
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(index, xpos, ypos, 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 control_enemy(struct Actor* enemy) {
|
||||
byte control = 0;
|
||||
int pdx = player->xx - enemy->xx;
|
||||
int pdy = player->yy - enemy->yy;
|
||||
if (pdy > 0) {
|
||||
control |= JOY_DOWN_MASK;
|
||||
} else if (pdy < 0) {
|
||||
control |= JOY_UP_MASK;
|
||||
}
|
||||
if (pdx < -32) {
|
||||
control |= JOY_LEFT_MASK;
|
||||
} else if (pdx > 32) {
|
||||
control |= JOY_RIGHT_MASK;
|
||||
}
|
||||
control_actor(enemy, control);
|
||||
}
|
||||
|
||||
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 enemy
|
||||
control_enemy(&actors[1]);
|
||||
// move the camera if needed
|
||||
camera_follow(player);
|
||||
// animate sprites in shadow sprite ram
|
||||
draw_actor(&actors[0], 0);
|
||||
draw_actor(&actors[1], 1);
|
||||
// wait for vblank
|
||||
wait_vblank();
|
||||
// then update sprite registers
|
||||
sprite_update(visbuf);
|
||||
// do scrolling stuff each frame
|
||||
scroll_update();
|
||||
}
|
||||
|
||||
void setup_sprites(void) {
|
||||
sprite_clear();
|
||||
sprite_set_shapes(SPRITE_DATA, 240, NUM_SPRITE_PATTERNS);
|
||||
sprshad.spr_color[0] = COLOR_WHITE;
|
||||
sprshad.spr_color[1] = COLOR_LIGHTRED;
|
||||
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 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);
|
||||
actors[1].xx = 128;
|
||||
|
||||
// infinite loop
|
||||
while (1) {
|
||||
next_frame();
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
include "cartheader.dasm"
|
||||
|
||||
; program start
|
||||
Temp equ $03
|
||||
Start
|
||||
sei ; turn off interrupts
|
||||
ldy #0
|
||||
sty $d020 ; reset border color
|
||||
Loop
|
||||
lda Message,y ; load message byte
|
||||
beq EOM ; 0 = end of string
|
||||
clc
|
||||
adc #$c0 ; + 192
|
||||
sta $400+41,y ; store to screen
|
||||
iny
|
||||
bne Loop ; next character
|
||||
EOM
|
||||
Wait1
|
||||
lda $d011
|
||||
bmi Wait1 ; wait for line < 256
|
||||
Wait2
|
||||
lda $d012 ; get current scanline
|
||||
Wait3
|
||||
cmp $d012
|
||||
beq Wait3 ; wait for scanline to change
|
||||
lsr
|
||||
lsr
|
||||
clc
|
||||
adc Temp
|
||||
sta $d020 ; set border color
|
||||
lda $d011 ; get status bits
|
||||
bpl Wait2 ; repeat until line >= 256
|
||||
sty $d020 ; reset border color
|
||||
dec Temp ; scroll colors
|
||||
jmp Wait1 ; endless loop
|
||||
Message
|
||||
; PETSCII - http://sta.c64.org/cbm64pet.html
|
||||
byte "HELLO`WORLDa"
|
||||
byte 0
|
131
presets/c64/joygame.c
Normal file
131
presets/c64/joygame.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
#define NUM_SPRITES 3
|
||||
|
||||
/*{w:12,h:21,bpp:2,brev:1,wpimg:64,count:3,aspect:2}*/
|
||||
const char SPRITE_MC_DATA[64*NUM_SPRITES] = {
|
||||
0x0A,0xAA,0x80,0x0A,0xAA,0x80,0x2A,0xAA,
|
||||
0xA0,0x2A,0xAA,0xA0,0xAA,0xAA,0xAA,0xFF,
|
||||
0xD5,0x40,0x0D,0xD7,0x40,0x3D,0xD5,0x54,
|
||||
0x37,0x55,0x54,0x37,0x55,0x54,0x35,0x55,
|
||||
0x00,0x3A,0xA0,0x00,0xEA,0xA8,0x00,0xAB,
|
||||
0xAA,0x00,0xAB,0xAA,0x00,0xAB,0xAA,0x80,
|
||||
0xAA,0xEA,0x80,0xAA,0xAA,0x80,0x0F,0xFC,
|
||||
0x00,0x0F,0xFC,0x00,0x0F,0xFF,0xC0,0x00,
|
||||
|
||||
0x02,0xAA,0xA0,0x02,0xAA,0xA0,0x0A,0xAA,
|
||||
0xA8,0x0A,0xAA,0xA8,0xAA,0xAA,0xAA,0x01,
|
||||
0x57,0xFF,0x01,0xD7,0x70,0x15,0x57,0x7C,
|
||||
0x15,0x55,0xDC,0x15,0x55,0xDC,0x00,0x55,
|
||||
0x5C,0x00,0x0A,0xAC,0x00,0x2A,0xAB,0x00,
|
||||
0xAA,0xEA,0x00,0xAA,0xEA,0x02,0xAA,0xEA,
|
||||
0x02,0xAB,0xAA,0x02,0xAA,0xAA,0x00,0x3F,
|
||||
0xF0,0x00,0x3F,0xF0,0x03,0xFF,0xF0,0x00,
|
||||
|
||||
0x00,0xAA,0x80,0x02,0xAA,0xA0,0x0A,0xAA,0xA8,
|
||||
0x0A,0xAE,0xA8,0x0A,0xBB,0xA8,0x0A,0xBA,0xA8,
|
||||
0x0A,0xBB,0xA8,0x0A,0xAE,0xA8,0x0A,0xAA,0xA8,
|
||||
0x09,0xAA,0x98,0x08,0x6A,0x48,0x08,0x1D,0x08,
|
||||
0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20,
|
||||
0x00,0x8C,0x80,0x00,0x8C,0x80,0x00,0x55,0x40,
|
||||
0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00,
|
||||
0x80,
|
||||
};
|
||||
|
||||
// starting index for sprites
|
||||
#define SPRITE_SHAPE 192
|
||||
|
||||
// player data
|
||||
int player_x = 172;
|
||||
byte player_y = 145;
|
||||
byte faceleft = 0; // 0 = face right, 1 = face left
|
||||
|
||||
void init_sprite_shapes(void) {
|
||||
byte i;
|
||||
for (i=0; i<NUM_SPRITES; i++) {
|
||||
sprite_shape(SPRITE_SHAPE+i, SPRITE_MC_DATA+64*i);
|
||||
}
|
||||
}
|
||||
|
||||
void init_sprite_positions(void) {
|
||||
byte i;
|
||||
// setup sprite positions
|
||||
player_x = 172;
|
||||
player_y = 145;
|
||||
// set random positions for non-players
|
||||
// and draw them to sprite shadow buffer
|
||||
srand(7);
|
||||
for (i=1; i<8; i++) {
|
||||
int x = rand() % (320 - 24) + 24;
|
||||
byte y = rand() % (229 - 50) + 50;
|
||||
sprite_draw(i, x, y, SPRITE_SHAPE + 2);
|
||||
sprshad.spr_color[i] = i | 8;
|
||||
}
|
||||
}
|
||||
|
||||
void move_player(byte joy) {
|
||||
// move sprite based on joystick
|
||||
if (JOY_LEFT(joy)) { player_x -= 1; faceleft = 1; } // move left 1 pixel
|
||||
if (JOY_RIGHT(joy)) { player_x += 1; faceleft = 0; } // move right 1 pixel
|
||||
if (JOY_UP(joy)) { player_y -= 1; } // move up 1 pixel
|
||||
if (JOY_DOWN(joy)) { player_y += 1; } // move down 1 pixel
|
||||
|
||||
// draw player into sprite shadow buffer
|
||||
sprite_draw(0, player_x, player_y, SPRITE_SHAPE + faceleft);
|
||||
}
|
||||
|
||||
void move_non_players(void) {
|
||||
byte i;
|
||||
// wiggle non-player sprites randomly
|
||||
for (i=1; i<8; i++) {
|
||||
sprshad.spr_pos[i].y += rand() & i;
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// variables
|
||||
byte bgcoll; // sprite background collision flags
|
||||
byte sprcoll; // sprite collision flags
|
||||
byte joy; // joystick flags
|
||||
|
||||
clrscr();
|
||||
|
||||
// install the joystick driver
|
||||
joy_install (joy_static_stddrv);
|
||||
|
||||
// set multicolor sprites and colors
|
||||
sprshad.spr_mcolor = 0b11111111;
|
||||
sprshad.spr_color[0] = SPRITE_MC_DATA[63];
|
||||
VIC.spr_mcolor0 = COLOR_GRAY2;
|
||||
VIC.spr_mcolor1 = COLOR_BLACK;
|
||||
|
||||
// setup sprites
|
||||
init_sprite_shapes();
|
||||
init_sprite_positions();
|
||||
|
||||
// loop forever
|
||||
while (1) {
|
||||
// wait for end of frame
|
||||
waitvsync();
|
||||
// update sprite registers from sprite shadow
|
||||
// buffer before frame starts drawing
|
||||
sprite_update(DEFAULT_SCREEN);
|
||||
|
||||
// get joystick bits
|
||||
joy = joy_read(0);
|
||||
move_player(joy);
|
||||
// move other objects
|
||||
move_non_players();
|
||||
|
||||
// grab and reset collision flags
|
||||
sprcoll = VIC.spr_coll;
|
||||
bgcoll = VIC.spr_bg_coll;
|
||||
// change color when player collides with sprite
|
||||
sprshad.spr_color[0] = (sprcoll & 1) ? 10 : 3;
|
||||
}
|
||||
}
|
|
@ -1,94 +1,59 @@
|
|||
// ported from
|
||||
// https://odensskjegg.home.blog/2018/12/29/recreating-the-commodore-64-user-guide-code-samples-in-cc65-part-three-sprites/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <peekpoke.h>
|
||||
#include <c64.h>
|
||||
#include <joystick.h>
|
||||
#include "common.h"
|
||||
|
||||
/*{w:24,h:21,bpp:1,brev:1}*/
|
||||
const char sprite[3*21] = {
|
||||
0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xE0,
|
||||
0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0,
|
||||
0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0,
|
||||
0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40,
|
||||
0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80,
|
||||
0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00,
|
||||
0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00
|
||||
/*{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}*/
|
||||
const char spritemc[3*21] = {
|
||||
0x00,0xFF,0xC0,0x03,0xFF,0xF0,0x0F,0xFF,0xFC,
|
||||
0x0F,0xFB,0xFC,0x0F,0xEE,0xFC,0x0F,0xEF,0xFC,
|
||||
0x0F,0xEE,0xFC,0x0F,0xFB,0xFC,0x0F,0xFF,0xFC,
|
||||
0x09,0xFF,0xD8,0x08,0x7F,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
|
||||
};
|
||||
void main(void) {
|
||||
// variables
|
||||
int x = 172; // sprite X position (16-bit)
|
||||
byte y = 145; // sprite Y position (8-bit)
|
||||
byte bgcoll; // sprite background collision flags
|
||||
byte joy; // joystick flags
|
||||
|
||||
// Raster wait with line argument
|
||||
void rasterWait(unsigned char line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
}
|
||||
// copy sprite pattern to RAM address 0x3800
|
||||
memcpy((char*)0x3800, SPRITE_DATA, sizeof(SPRITE_DATA));
|
||||
// set sprite #0 shape entry (224)
|
||||
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;
|
||||
|
||||
int main (void)
|
||||
{
|
||||
int n;
|
||||
int x,y;
|
||||
char bgcoll;
|
||||
// install the joystick driver
|
||||
joy_install (joy_static_stddrv);
|
||||
// set background color
|
||||
VIC.bgcolor0 = 3;
|
||||
// clear interrupts to avoid glitching
|
||||
__asm__("SEI");
|
||||
// set sprite bitmap data
|
||||
for (n = 0 ; n < sizeof(sprite) ; n++) {
|
||||
POKE(0x340 + n, sprite[n]);
|
||||
POKE(0x380 + n, spritemc[n]);
|
||||
}
|
||||
// enable 1st and 2nd sprite
|
||||
VIC.spr_ena = 0x03;
|
||||
VIC.spr_mcolor = 0x02;
|
||||
// set colors
|
||||
VIC.spr_mcolor0 = 4;
|
||||
VIC.spr_mcolor1 = 7;
|
||||
// 2x zoom 1st sprite
|
||||
VIC.spr_exp_x = 0x01;
|
||||
VIC.spr_exp_y = 0x01;
|
||||
// set address of sprite data
|
||||
POKE(0x7f8, 13);
|
||||
POKE(0x7f9, 14);
|
||||
// set initial x/y positions
|
||||
x = 160;
|
||||
y = 128;
|
||||
// loop
|
||||
|
||||
// loop forever
|
||||
while (1) {
|
||||
// get joystick bits
|
||||
char joy = joy_read(0);
|
||||
// move sprite based on arrow keys
|
||||
if (JOY_LEFT(joy)) --x;
|
||||
if (JOY_UP(joy)) --y;
|
||||
if (JOY_RIGHT(joy)) ++x;
|
||||
if (JOY_DOWN(joy)) ++y;
|
||||
// set VIC registers based on position
|
||||
VIC.spr0_x = x;
|
||||
VIC.spr0_y = y-32;
|
||||
VIC.spr1_x = x;
|
||||
VIC.spr1_y = y+32;
|
||||
VIC.spr_hi_x = (x & 256) ? 1 : 0;
|
||||
// change color when we collide with background
|
||||
bgcoll = VIC.spr_bg_coll;
|
||||
VIC.spr0_color = (bgcoll & 1) ? 10 : 0;
|
||||
VIC.spr1_color = (bgcoll & 2) ? 10 : 0;
|
||||
joy = joy_read(0);
|
||||
// move sprite based on joystick
|
||||
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
|
||||
rasterWait(255);
|
||||
waitvsync();
|
||||
// set sprite registers based on position
|
||||
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.spr_color[0] = (bgcoll & 1) ?
|
||||
COLOR_LIGHTRED : COLOR_CYAN;
|
||||
}
|
||||
// uninstall joystick driver (not really necessary)
|
||||
joy_uninstall();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -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,12 +70,13 @@ void mandelbrot (signed short x1, signed short y1, signed short x2,
|
|||
if (count == maxiterations) {
|
||||
color = (0);
|
||||
} else {
|
||||
color = COLORS[count % MAXCOL];
|
||||
}
|
||||
/* Set pixel */
|
||||
color = count < MAXCOL
|
||||
? COLORS[count]
|
||||
: COLORS[MAXCOL-1];
|
||||
set_pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main (void)
|
||||
|
@ -85,7 +85,7 @@ 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 ();
|
||||
|
|
|
@ -1,36 +1,35 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <c64.h>
|
||||
#include <peekpoke.h>
|
||||
|
||||
#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_BITMAP(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;
|
||||
|
@ -40,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);
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
|
@ -91,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;
|
16
presets/c64/mcbitmap.h
Normal file
16
presets/c64/mcbitmap.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
#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);
|
||||
|
205
presets/c64/multisprite.ca65
Normal file
205
presets/c64/multisprite.ca65
Normal file
|
@ -0,0 +1,205 @@
|
|||
|
||||
MAX_MSPRITES = 28
|
||||
|
||||
MIN_Y_SPACING = 35
|
||||
|
||||
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
|
||||
.global _msprite_last_y
|
||||
|
||||
_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
|
||||
_msprite_last_y:.res 1
|
||||
|
||||
.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
|
|
@ -3,10 +3,6 @@
|
|||
A simple music player.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <c64.h>
|
||||
#include <_sid.h>
|
||||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
|
@ -20,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) \
|
||||
|
|
92
presets/c64/rasterirq.ca65
Normal file
92
presets/c64/rasterirq.ca65
Normal file
|
@ -0,0 +1,92 @@
|
|||
|
||||
USE_INTERRUPTOR = 0
|
||||
|
||||
.segment "DATA"
|
||||
|
||||
StartDlist: .word NullDlist-1
|
||||
NextDlist: .word NullDlist-1
|
||||
|
||||
.segment "CODE"
|
||||
|
||||
.global ___dlist_setup
|
||||
.global DLIST_IRQ_NEXT
|
||||
.global DLIST_IRQ_RESTART
|
||||
.if USE_INTERRUPTOR
|
||||
.interruptor DLIST_IRQ
|
||||
.endif
|
||||
|
||||
___dlist_setup:
|
||||
SEI ; set interrupt bit, make the CPU ignore interrupt requests
|
||||
|
||||
sta StartDlist+0 ; save XA as pointer to start of dlist
|
||||
stx StartDlist+1
|
||||
|
||||
LDA #%01111111 ; switch off interrupt signals from CIA-1
|
||||
STA $DC0D
|
||||
|
||||
AND $D011 ; clear most significant bit of VIC's raster register
|
||||
STA $D011
|
||||
|
||||
LDA $DC0D ; acknowledge pending interrupts from CIA-1
|
||||
LDA $DD0D ; acknowledge pending interrupts from CIA-2
|
||||
|
||||
LDA #252 ; set rasterline where interrupt shall occur
|
||||
STA $D012
|
||||
|
||||
.if !USE_INTERRUPTOR
|
||||
LDA #<DLIST_IRQ ; set interrupt vectors, pointing to interrupt service routine below
|
||||
STA $0314
|
||||
LDA #>DLIST_IRQ
|
||||
STA $0315
|
||||
.endif
|
||||
|
||||
LDA #%00000001 ; enable raster interrupt signals from VIC
|
||||
STA $D01A
|
||||
cli
|
||||
rts
|
||||
|
||||
DLIST_IRQ:
|
||||
DLIST_CALL:
|
||||
lda NextDlist+1
|
||||
pha
|
||||
lda NextDlist+0
|
||||
pha
|
||||
rts
|
||||
|
||||
DLIST_IRQ_RESTART:
|
||||
sta $d012
|
||||
lda StartDlist+0
|
||||
sta NextDlist+0
|
||||
lda StartDlist+1
|
||||
sta NextDlist+1
|
||||
bne DLIST_ACK
|
||||
|
||||
DLIST_IRQ_STOP:
|
||||
lda #0 ; disable raster interrupt signals from VIC
|
||||
sta $D01A
|
||||
bne DLIST_ACK
|
||||
|
||||
DLIST_IRQ_NEXT:
|
||||
sta $d012
|
||||
pla
|
||||
sta NextDlist+0
|
||||
pla
|
||||
sta NextDlist+1
|
||||
DLIST_ACK:
|
||||
ASL $D019 ; acknowledge the interrupt by clearing the VIC's interrupt flag
|
||||
.if USE_INTERRUPTOR
|
||||
clc
|
||||
rts
|
||||
.else
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rti ; return from interrupt
|
||||
; JMP $EA31 ; jump into KERNAL's standard interrupt service routine to handle keyboard scan, cursor display etc.
|
||||
.endif
|
||||
|
||||
NullDlist:
|
||||
lda #252
|
||||
jmp DLIST_IRQ_RESTART
|
23
presets/c64/rasterirq.h
Normal file
23
presets/c64/rasterirq.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef _RASTERIRQ_H
|
||||
#define _RASTERIRQ_H
|
||||
|
||||
|
||||
// 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)
|
||||
|
||||
// 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");
|
||||
|
||||
|
||||
#endif
|
|
@ -1,48 +1,72 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <c64.h>
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include <cbm_petscii_charmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
#define SCROLL_TOP 0
|
||||
#define SCROLL_ROWS 10
|
||||
|
||||
void rasterWait(unsigned char line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
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;
|
||||
}
|
||||
|
||||
byte x = 0; // x scroll position
|
||||
byte y = 0; // y scroll position
|
||||
byte* scrnbuf; // screen buffer
|
||||
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
|
||||
rasterWait(255);
|
||||
// every 8 pixels, move screen cells
|
||||
if ((x & 7) == 0) {
|
||||
memcpy(scrnbuf, scrnbuf+1, 40*8-1);
|
||||
}
|
||||
waitvsync();
|
||||
// scroll one pixel to the left
|
||||
// and move screen memory every 8 pixels
|
||||
scroll_one_pixel_left();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,58 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <c64.h>
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include <cbm_petscii_charmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
#define BUFFER_0 0x400
|
||||
#define BUFFER_1 0x3c00
|
||||
|
||||
void rasterWait(unsigned char line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
}
|
||||
|
||||
byte x = 0; // x scroll position
|
||||
byte y = 0; // y scroll position
|
||||
byte scroll_x = 0; // x scroll position
|
||||
byte* scrnbuf[2]; // screen buffer(s)
|
||||
byte frame = 0;
|
||||
byte visbuf; // which buffer is visible? 0 or 1
|
||||
|
||||
void main(void) {
|
||||
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
|
||||
rasterWait(255);
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +1,45 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <c64.h>
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include <cbm_petscii_charmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <joystick.h>
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
typedef int8_t sbyte;
|
||||
|
||||
#define COLS 40
|
||||
#define ROWS 25
|
||||
|
||||
void raster_wait(unsigned char line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
}
|
||||
|
||||
void wait_vblank() {
|
||||
raster_wait(255); // TODO
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -92,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;
|
||||
SET_VIC_BANK(0x8000);
|
||||
|
||||
VIC.ctrl1 = 0x10; // 24 lines
|
||||
VIC.ctrl2 = 0x00; // 38 columns
|
||||
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);
|
||||
|
@ -129,7 +111,7 @@ void main(void) {
|
|||
if (JOY_RIGHT(joy)) scroll_horiz(1);
|
||||
if (JOY_DOWN(joy)) scroll_vert(1);
|
||||
// update regs
|
||||
wait_vblank();
|
||||
waitvsync();
|
||||
scroll_update_regs();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,166 +1,54 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <c64.h>
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "scrolling.h"
|
||||
//#link "scrolling.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
#include <cbm_petscii_charmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <joystick.h>
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
typedef int8_t sbyte;
|
||||
|
||||
#define COLS 40
|
||||
#define ROWS 25
|
||||
|
||||
void raster_wait(unsigned char line) {
|
||||
while (VIC.rasterline < line) ;
|
||||
}
|
||||
|
||||
void wait_vblank() {
|
||||
raster_wait(255); // TODO
|
||||
}
|
||||
|
||||
sbyte scroll_fine_x;
|
||||
sbyte scroll_fine_y;
|
||||
byte origin_x;
|
||||
byte origin_y;
|
||||
byte curbuf;
|
||||
byte* scrnbuf[2]; // screen buffer(s)
|
||||
byte tempbuf[COLS*ROWS];
|
||||
|
||||
void draw_cell(byte x, byte y) {
|
||||
static void draw_cell(word ofs, byte x, byte y) {
|
||||
byte xx = x + origin_x;
|
||||
byte yy = y + origin_y;
|
||||
byte ch = xx ^ yy;
|
||||
word ofs = x+y*COLS;
|
||||
scrnbuf[curbuf][ofs] = ch; // character
|
||||
tempbuf[ofs] = ch; // color
|
||||
hidbuf[ofs] = ch; // character
|
||||
colorbuf[ofs] = ch; // color
|
||||
}
|
||||
|
||||
void scroll_draw_column(byte col) {
|
||||
byte y;
|
||||
word ofs = col;
|
||||
for (y=0; y<ROWS; y++) {
|
||||
draw_cell(col, 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(x, row);
|
||||
draw_cell(ofs, x, row);
|
||||
++ofs;
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_update_regs() {
|
||||
VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | scroll_fine_y;
|
||||
VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | scroll_fine_x;
|
||||
}
|
||||
|
||||
void scroll_swap() {
|
||||
// swap hidden and visible buffers
|
||||
curbuf ^= 1;
|
||||
// wait for vblank and update registers
|
||||
wait_vblank();
|
||||
scroll_update_regs();
|
||||
VIC.addr = (VIC.addr & 0xf) | (curbuf ? 0x00 : 0x10);
|
||||
}
|
||||
|
||||
void scroll_copy() {
|
||||
// copy temp buf to color ram
|
||||
memcpy(COLOR_RAM, tempbuf, COLS*ROWS);
|
||||
// copy visible buffer to hidden buffer
|
||||
memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1], COLS*ROWS);
|
||||
}
|
||||
|
||||
// TODO: left and up can be faster, b/c we can copy color ram downward
|
||||
|
||||
void scroll_left() {
|
||||
memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1]+1, COLS*ROWS-1);
|
||||
++origin_x;
|
||||
memcpy(tempbuf, COLOR_RAM+1, COLS*ROWS-1);
|
||||
scroll_draw_column(COLS-1);
|
||||
scroll_swap();
|
||||
scroll_copy();
|
||||
}
|
||||
|
||||
void scroll_up() {
|
||||
memcpy(scrnbuf[curbuf], scrnbuf[curbuf^1]+COLS, COLS*(ROWS-1));
|
||||
++origin_y;
|
||||
memcpy(tempbuf, COLOR_RAM+COLS, COLS*(ROWS-1));
|
||||
scroll_draw_row(ROWS-1);
|
||||
scroll_swap();
|
||||
scroll_copy();
|
||||
}
|
||||
|
||||
void scroll_right() {
|
||||
memcpy(scrnbuf[curbuf]+1, scrnbuf[curbuf^1], COLS*ROWS-1);
|
||||
--origin_x;
|
||||
memcpy(tempbuf+1, COLOR_RAM, COLS*ROWS-1);
|
||||
scroll_draw_column(0);
|
||||
scroll_swap();
|
||||
scroll_copy();
|
||||
}
|
||||
|
||||
void scroll_down() {
|
||||
memcpy(scrnbuf[curbuf]+COLS, scrnbuf[curbuf^1], COLS*(ROWS-1));
|
||||
--origin_y;
|
||||
memcpy(tempbuf+COLS, COLOR_RAM, COLS*(ROWS-1));
|
||||
scroll_draw_row(0);
|
||||
scroll_swap();
|
||||
scroll_copy();
|
||||
}
|
||||
|
||||
void scroll_horiz(sbyte delta_x) {
|
||||
scroll_fine_x += delta_x;
|
||||
while (scroll_fine_x < 0) {
|
||||
scroll_fine_x += 8;
|
||||
scroll_left();
|
||||
}
|
||||
while (scroll_fine_x >= 8) {
|
||||
scroll_fine_x -= 8;
|
||||
scroll_right();
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_vert(sbyte delta_y) {
|
||||
scroll_fine_y += delta_y;
|
||||
while (scroll_fine_y < 0) {
|
||||
scroll_fine_y += 8;
|
||||
scroll_up();
|
||||
}
|
||||
while (scroll_fine_y >= 8) {
|
||||
scroll_fine_y -= 8;
|
||||
scroll_down();
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_setup() {
|
||||
scroll_fine_x = 0;
|
||||
scroll_fine_y = 0;
|
||||
origin_x = 0x80;
|
||||
origin_y = 0x80;
|
||||
curbuf = 0;
|
||||
// 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)
|
||||
// https://www.c64-wiki.com/wiki/VIC_bank
|
||||
CIA2.pra = 0x01;
|
||||
|
||||
VIC.ctrl1 = 0x10; // 24 lines
|
||||
VIC.ctrl2 = 0x00; // 38 columns
|
||||
}
|
||||
/*{w:24,h:21,bpp:1,brev:1}*/
|
||||
const char SPRITE1[3*21] = {
|
||||
0x80,0x7F,0x01,0x01,0xFF,0xC0,0x03,0xFF,0xE0,
|
||||
0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0,
|
||||
0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0,
|
||||
0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40,
|
||||
0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80,
|
||||
0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00,
|
||||
0x00,0x3E,0x00,0x00,0x3E,0x00,0x80,0x1C,0x01
|
||||
};
|
||||
|
||||
void main(void) {
|
||||
sbyte n =0;
|
||||
byte n = 0;
|
||||
|
||||
clrscr();
|
||||
printf("\r\n\r\n\r\n Hello World!");
|
||||
|
@ -169,22 +57,38 @@ void main(void) {
|
|||
printf("\r\n\r\n\r\n So we have to use a temp buffer");
|
||||
printf("\r\n\r\n\r\n And copy it just in time");
|
||||
|
||||
// setup scrolling library
|
||||
scroll_setup();
|
||||
VIC.bordercolor = 12;
|
||||
|
||||
// setup sprite library and copy sprite to VIC bank
|
||||
sprite_clear();
|
||||
sprite_set_shapes(SPRITE1, 192, 1);
|
||||
|
||||
// install the joystick driver
|
||||
joy_install (joy_static_stddrv);
|
||||
|
||||
// infinite loop
|
||||
while (1) {
|
||||
static char speed = 1;
|
||||
// get joystick bits
|
||||
char joy = joy_read(0);
|
||||
// speed up scrolling while button pressed
|
||||
speed = JOY_BTN_1(joy) ? 2 : 1;
|
||||
// move sprite based on arrow keys
|
||||
if (JOY_LEFT(joy)) scroll_horiz(-1);
|
||||
if (JOY_UP(joy)) scroll_vert(-1);
|
||||
if (JOY_RIGHT(joy)) scroll_horiz(1);
|
||||
if (JOY_DOWN(joy)) scroll_vert(1);
|
||||
// update regs
|
||||
wait_vblank();
|
||||
scroll_update_regs();
|
||||
if (JOY_LEFT(joy)) scroll_horiz(-speed);
|
||||
if (JOY_UP(joy)) scroll_vert(-speed);
|
||||
if (JOY_RIGHT(joy)) scroll_horiz(speed);
|
||||
if (JOY_DOWN(joy)) scroll_vert(speed);
|
||||
// animate sprite in shadow sprite ram
|
||||
sprite_draw(0, n++, 70, 192);
|
||||
sprite_draw(0, 172, 145, 192);
|
||||
// wait for vblank
|
||||
waitvsync();
|
||||
// update scroll registers
|
||||
// and swap screens if we must
|
||||
scroll_update();
|
||||
// then update sprite registers
|
||||
sprite_update(visbuf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
|
||||
#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>
|
||||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
|
@ -17,26 +8,31 @@
|
|||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
static void draw_cell(byte x, byte y) {
|
||||
#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;
|
||||
byte ch = xx ^ yy;
|
||||
word ofs = x+y*COLS;
|
||||
hidbuf[ofs] = ch; // character
|
||||
colorbuf[ofs] = ch; // color
|
||||
}
|
||||
|
||||
void scroll_draw_column(byte col) {
|
||||
byte y;
|
||||
word ofs = col;
|
||||
for (y=0; y<ROWS; y++) {
|
||||
draw_cell(col, 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(x, row);
|
||||
draw_cell(ofs, x, row);
|
||||
++ofs;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,43 +47,82 @@ const char SPRITE1[3*21] = {
|
|||
0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00
|
||||
};
|
||||
|
||||
int playerx = 0;
|
||||
int playery = 0;
|
||||
int camerax = 0;
|
||||
int cameray = 0;
|
||||
|
||||
void update_player() {
|
||||
sprite_draw(0, playerx-camerax+160, playery-cameray+140, 192);
|
||||
}
|
||||
|
||||
void camera_follow(byte moving) {
|
||||
int dx, dy;
|
||||
dx = camerax - playerx;
|
||||
dy = cameray - playery;
|
||||
if (moving && abs(dx) < 32 && abs(dy) < 32) return;
|
||||
dx >>= 4;
|
||||
dy >>= 4;
|
||||
if (dx) {
|
||||
if (dx > 8) dx = 8;
|
||||
else if (dx < -8) dx = -8;
|
||||
camerax -= dx;
|
||||
}
|
||||
if (dy) {
|
||||
if (dy > 8) dy = 8;
|
||||
else if (dy < -8) dy = -8;
|
||||
cameray -= dy;
|
||||
}
|
||||
scroll_xy(dx, dy);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
byte n = 0;
|
||||
|
||||
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 But color RAM can't move");
|
||||
printf("\r\n\r\n\r\n So we have to use a temp buffer");
|
||||
printf("\r\n\r\n\r\n And copy it just in time");
|
||||
printf("\r\n\r\n\r\n Use the joystick to move");
|
||||
printf("\r\n\r\n\r\n And the camera will follow");
|
||||
|
||||
// setup scrolling library
|
||||
scroll_setup();
|
||||
VIC.bordercolor = 12;
|
||||
|
||||
// setup sprite library and copy sprite to VIC bank
|
||||
sprite_clear();
|
||||
sprite_shape(hidbuf, 32, SPRITE1);
|
||||
sprite_set_shapes(SPRITE1, 192, 1);
|
||||
sprshad.spr_color[0] = 13;
|
||||
|
||||
// install the joystick driver
|
||||
joy_install (joy_static_stddrv);
|
||||
|
||||
// infinite loop
|
||||
while (1) {
|
||||
static char speed;
|
||||
static char joy;
|
||||
static bool slowframe = false;
|
||||
// get joystick bits
|
||||
char joy = joy_read(0);
|
||||
joy = joy_read(0);
|
||||
// speed up scrolling while button pressed
|
||||
speed = JOY_BTN_1(joy) ? 3 : 1;
|
||||
// if we copied screen memory last frame,
|
||||
// double speed of player for this frame
|
||||
if (slowframe) speed *= 2;
|
||||
// move sprite based on arrow keys
|
||||
if (JOY_LEFT(joy)) scroll_horiz(-1);
|
||||
if (JOY_UP(joy)) scroll_vert(-1);
|
||||
if (JOY_RIGHT(joy)) scroll_horiz(1);
|
||||
if (JOY_DOWN(joy)) scroll_vert(1);
|
||||
if (JOY_LEFT(joy)) playerx -= speed;
|
||||
if (JOY_RIGHT(joy)) playerx += speed;
|
||||
if (JOY_UP(joy)) playery -= speed;
|
||||
if (JOY_DOWN(joy)) playery += speed;
|
||||
// move the camera?
|
||||
camera_follow(joy);
|
||||
slowframe = swap_needed;
|
||||
// animate sprite in shadow sprite ram
|
||||
sprite_draw(0, n++, 70, 32);
|
||||
// wait for vblank
|
||||
wait_vblank();
|
||||
update_player();
|
||||
// wait for end of frame
|
||||
waitvsync();
|
||||
// then update sprite registers
|
||||
sprite_update(visbuf);
|
||||
// update scroll registers
|
||||
// and swap screens if we must
|
||||
scroll_update();
|
||||
// then update sprite registers
|
||||
sprite_update(visbuf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,53 +11,123 @@ byte* hidbuf;
|
|||
byte* visbuf;
|
||||
byte colorbuf[COLS*ROWS];
|
||||
byte swap_needed;
|
||||
byte copy_needed;
|
||||
|
||||
//
|
||||
|
||||
void scroll_swap(void) {
|
||||
void scroll_swap() {
|
||||
byte* tmp;
|
||||
// set VIC bank address
|
||||
VIC.addr = (VIC.addr & 0xf) | (((word)hidbuf >> 8) << 2);
|
||||
// swap hidden and visible buffers
|
||||
tmp = hidbuf;
|
||||
hidbuf = visbuf;
|
||||
visbuf = tmp;
|
||||
// set VIC bank address
|
||||
SET_VIC_SCREEN((word)visbuf);
|
||||
}
|
||||
|
||||
void scroll_copy(void) {
|
||||
// copy temp buf to color ram
|
||||
void copy_color_ram_slow() {
|
||||
memcpy(COLOR_RAM, colorbuf, COLS*ROWS);
|
||||
// copy visible buffer to hidden buffer
|
||||
}
|
||||
|
||||
void copy_color_ram_fast() {
|
||||
// fast copy loop for upper 1/2 of color ram
|
||||
asm("ldy #0");
|
||||
asm("@loop:");
|
||||
asm("lda %v,y", colorbuf);
|
||||
asm("sta $d800,y");
|
||||
asm("lda %v + $100,y", colorbuf);
|
||||
asm("sta $d900,y");
|
||||
asm("iny");
|
||||
asm("bne @loop");
|
||||
// second loop for lower 1/2 of color ram
|
||||
asm("@loop2:");
|
||||
asm("lda %v + $200,y", colorbuf);
|
||||
asm("sta $da00,y");
|
||||
asm("lda %v + $300,y", colorbuf);
|
||||
asm("sta $db00,y");
|
||||
asm("@skip: iny");
|
||||
asm("bne @loop2");
|
||||
}
|
||||
|
||||
void copy_to_hidden_buffer_slow() {
|
||||
memcpy(hidbuf, visbuf, COLS*ROWS);
|
||||
}
|
||||
|
||||
void scroll_update(void) {
|
||||
VIC.ctrl1 = (VIC.ctrl1 & 0xf8) | scroll_fine_y;
|
||||
VIC.ctrl2 = (VIC.ctrl2 & 0xf8) | scroll_fine_x;
|
||||
if (swap_needed) {
|
||||
scroll_swap();
|
||||
scroll_copy();
|
||||
swap_needed = 0;
|
||||
void copy_to_hidden_buffer_fast() {
|
||||
// self-modifying code
|
||||
asm("ldy %v+1", visbuf);
|
||||
asm("sty @loop+2+6*0");
|
||||
asm("iny");
|
||||
asm("sty @loop+2+6*1");
|
||||
asm("iny");
|
||||
asm("sty @loop+2+6*2");
|
||||
asm("iny");
|
||||
asm("sty @skip-1-3");
|
||||
asm("ldy %v+1", hidbuf);
|
||||
asm("sty @loop+5+6*0");
|
||||
asm("iny");
|
||||
asm("sty @loop+5+6*1");
|
||||
asm("iny");
|
||||
asm("sty @loop+5+6*2");
|
||||
asm("iny");
|
||||
asm("sty @skip-1");
|
||||
// fast copy loop
|
||||
asm("ldy #0");
|
||||
asm("@loop:");
|
||||
asm("lda $8000,y");
|
||||
asm("sta $8000,y");
|
||||
asm("lda $8100,y");
|
||||
asm("sta $8100,y");
|
||||
asm("lda $8200,y");
|
||||
asm("sta $8200,y");
|
||||
asm("cpy #$e8");
|
||||
asm("bcs @skip");
|
||||
asm("lda $8300,y");
|
||||
asm("sta $8300,y");
|
||||
asm("@skip: iny");
|
||||
asm("bne @loop");
|
||||
}
|
||||
|
||||
void copy_if_needed() {
|
||||
if (copy_needed) {
|
||||
copy_to_hidden_buffer_fast();
|
||||
copy_needed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_left(void) {
|
||||
memcpy(hidbuf, hidbuf+1, COLS*ROWS-1);
|
||||
memcpy(colorbuf, colorbuf+1, COLS*ROWS-1);
|
||||
void scroll_update() {
|
||||
SET_SCROLL_X(scroll_fine_x);
|
||||
SET_SCROLL_Y(scroll_fine_y);
|
||||
if (swap_needed) {
|
||||
scroll_swap();
|
||||
copy_color_ram_fast();
|
||||
swap_needed = false;
|
||||
copy_needed = true;
|
||||
} else {
|
||||
copy_if_needed();
|
||||
}
|
||||
}
|
||||
|
||||
static void scroll_left() {
|
||||
copy_if_needed();
|
||||
memmove(hidbuf, hidbuf+1, COLS*ROWS-1);
|
||||
memmove(colorbuf, colorbuf+1, COLS*ROWS-1);
|
||||
++origin_x;
|
||||
scroll_draw_column(COLS-1);
|
||||
swap_needed = true;
|
||||
}
|
||||
|
||||
void scroll_up(void) {
|
||||
memcpy(hidbuf, hidbuf+COLS, COLS*(ROWS-1));
|
||||
memcpy(colorbuf, colorbuf+COLS, COLS*(ROWS-1));
|
||||
static void scroll_up() {
|
||||
copy_if_needed();
|
||||
memmove(hidbuf, hidbuf+COLS, COLS*(ROWS-1));
|
||||
memmove(colorbuf, colorbuf+COLS, COLS*(ROWS-1));
|
||||
++origin_y;
|
||||
scroll_draw_row(ROWS-1);
|
||||
swap_needed = true;
|
||||
}
|
||||
|
||||
void scroll_right(void) {
|
||||
static void scroll_right() {
|
||||
copy_if_needed();
|
||||
memmove(hidbuf+1, hidbuf, COLS*ROWS-1);
|
||||
memmove(colorbuf+1, colorbuf, COLS*ROWS-1);
|
||||
--origin_x;
|
||||
|
@ -65,7 +135,8 @@ void scroll_right(void) {
|
|||
swap_needed = true;
|
||||
}
|
||||
|
||||
void scroll_down(void) {
|
||||
static void scroll_down() {
|
||||
copy_if_needed();
|
||||
memmove(hidbuf+COLS, hidbuf, COLS*(ROWS-1));
|
||||
memmove(colorbuf+COLS, colorbuf, COLS*(ROWS-1));
|
||||
--origin_y;
|
||||
|
@ -97,23 +168,31 @@ void scroll_vert(sbyte delta_y) {
|
|||
}
|
||||
}
|
||||
|
||||
void scroll_setup(void) {
|
||||
scroll_fine_x = scroll_fine_y = 0;
|
||||
origin_x = origin_y = 0x80;
|
||||
swap_needed = true;
|
||||
void scroll_xy(sbyte delta_x, sbyte delta_y) {
|
||||
if (delta_x) scroll_horiz(delta_x);
|
||||
if (delta_y) scroll_vert(delta_y);
|
||||
}
|
||||
|
||||
// get screen buffer addresses
|
||||
void scroll_setup() {
|
||||
scroll_fine_x = scroll_fine_y = 0;
|
||||
origin_x = origin_y = 0;
|
||||
swap_needed = true;
|
||||
copy_needed = true;
|
||||
|
||||
// setup screen buffer addresses
|
||||
hidbuf = (byte*) 0x8000;
|
||||
visbuf = (byte*) 0x8400;
|
||||
// copy existing text to screen 0
|
||||
|
||||
// copy existing screen contents to hidden buffer
|
||||
memcpy(hidbuf, (byte*)0x400, COLS*ROWS);
|
||||
// copy screen 1 to screen 0
|
||||
// copy also to hidden buffer
|
||||
memcpy(visbuf, hidbuf, COLS*ROWS);
|
||||
|
||||
// set VIC bank ($4000-$7FFF)
|
||||
// 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
|
||||
VIC.ctrl2 &= ~0x08; // 38 columns
|
||||
}
|
||||
|
|
|
@ -20,14 +20,32 @@ extern byte swap_needed; // TRUE if scroll_update() swaps
|
|||
void scroll_setup(void);
|
||||
|
||||
// scroll in X or Y directions
|
||||
void scroll_xy(sbyte delta_x, sbyte delta_y);
|
||||
void scroll_horiz(sbyte delta_x);
|
||||
void scroll_vert(sbyte delta_y);
|
||||
|
||||
// call this after vblank
|
||||
// call this right after vblank
|
||||
void scroll_update(void);
|
||||
|
||||
// caller must implement these two
|
||||
void scroll_draw_column(byte col);
|
||||
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);
|
||||
void scroll_refresh(void);
|
||||
|
||||
#define SCROLL_LEFT 1
|
||||
#define SCROLL_RIGHT 2
|
||||
#define SCROLL_UP 4
|
||||
#define SCROLL_DOWN 8
|
||||
|
||||
|
||||
#endif
|
||||
|
|
162
presets/c64/scrolling_text.c
Normal file
162
presets/c64/scrolling_text.c
Normal file
File diff suppressed because one or more lines are too long
93
presets/c64/siddemo.c
Normal file
93
presets/c64/siddemo.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include <tgi.h>
|
||||
|
||||
//#resource "c64-sid.cfg"
|
||||
#define CFGFILE c64-sid.cfg
|
||||
|
||||
//#resource "sidmusic1.bin"
|
||||
//#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) {
|
||||
// install TGI graphics driver
|
||||
tgi_install(tgi_static_stddrv);
|
||||
tgi_init();
|
||||
tgi_clear();
|
||||
tgi_setpalette(Palette);
|
||||
|
||||
// initialize SID player
|
||||
sid_init(0);
|
||||
sid_start();
|
||||
|
||||
// install joystick driver
|
||||
joy_install(joy_static_stddrv);
|
||||
|
||||
while (1) {
|
||||
// play sound effect when joystick is moved
|
||||
byte joy = joy_read(0);
|
||||
if (joy) {
|
||||
sid_sfx(joy & 3);
|
||||
// exit when fire button pressed
|
||||
if (JOY_BTN_1(joy)) { break; }
|
||||
}
|
||||
// sync with frame rate
|
||||
waitvsync();
|
||||
// update SID player
|
||||
sid_update();
|
||||
// update graphs
|
||||
show_envelope();
|
||||
show_signal();
|
||||
}
|
||||
|
||||
tgi_uninstall();
|
||||
sid_stop();
|
||||
}
|
341
presets/c64/side_scroller.c
Normal file
341
presets/c64/side_scroller.c
Normal file
|
@ -0,0 +1,341 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
#include "rasterirq.h"
|
||||
//#link "rasterirq.ca65"
|
||||
|
||||
#include "bcd.h"
|
||||
//#link "bcd.c"
|
||||
|
||||
#include "sidmacros.h"
|
||||
|
||||
///// SPRITE DATA
|
||||
|
||||
#define NUM_SPRITE_PATTERNS 4
|
||||
|
||||
/*{w:12,h:21,bpp:2,brev:1,wpimg:64,count:4,aspect:2}*/
|
||||
const char SPRITE_DATA[64*NUM_SPRITE_PATTERNS] = {
|
||||
0x0A,0xAA,0x80,0x0A,0xAA,0x80,0x2A,0xAA,
|
||||
0xA0,0x2A,0xAA,0xA0,0xAA,0xAA,0xA8,0xFF,
|
||||
0xD5,0x40,0xCD,0xD7,0x40,0x3D,0xD5,0x54,
|
||||
0x37,0x55,0x54,0x37,0x54,0x50,0x05,0x55,
|
||||
0x00,0x3A,0xA0,0x00,0xEA,0xA8,0x00,0xAB,
|
||||
0xAA,0x00,0xAB,0xAA,0x00,0xAB,0xAA,0x80,
|
||||
0xAA,0xEA,0x80,0xAA,0xAA,0x80,0x0F,0xFC,
|
||||
0x00,0x0F,0xFC,0x00,0x0F,0xFF,0xC0,0x00,
|
||||
|
||||
0x02,0xAA,0xA0,0x02,0xAA,0xA0,0x0A,0xAA,
|
||||
0xA8,0x0A,0xAA,0xA8,0x2A,0xAA,0xAA,0x01,
|
||||
0x57,0xFF,0x01,0xD7,0x73,0x15,0x57,0x7C,
|
||||
0x15,0x55,0xDC,0x05,0x15,0xDC,0x00,0x55,
|
||||
0x50,0x00,0x0A,0xAC,0x00,0x2A,0xAB,0x00,
|
||||
0xAA,0xEA,0x00,0xAA,0xEA,0x02,0xAA,0xEA,
|
||||
0x02,0xAB,0xAA,0x02,0xAA,0xAA,0x00,0x3F,
|
||||
0xF0,0x00,0x3F,0xF0,0x03,0xFF,0xF0,0x00,
|
||||
|
||||
0x03,0xFF,0xF0,0x0E,0xAA,0xAC,0x0E,0xAA,0xAC,
|
||||
0x3A,0xAE,0xAB,0x3A,0xBB,0xAB,0x3A,0xBA,0xAB,
|
||||
0x3A,0xBB,0xAB,0x3A,0xAE,0xAB,0x3A,0xAA,0xAB,
|
||||
0x35,0xAA,0x97,0x04,0x6A,0x44,0x04,0x15,0x04,
|
||||
0x01,0x04,0x10,0x01,0x04,0x10,0x01,0x04,0x10,
|
||||
0x00,0x44,0x40,0x00,0x44,0x40,0x00,0xEA,0xC0,
|
||||
0x00,0xD9,0xC0,0x00,0xE6,0xC0,0x00,0x3F,0x00,
|
||||
0x00,
|
||||
|
||||
0x00,0x00,0x00,0x00,0xFF,0x00,0x03,0xAA,
|
||||
0xC0,0x0E,0xAA,0xB0,0x3A,0xAA,0xAC,0xE9,
|
||||
0x69,0x6B,0xEA,0x69,0xAB,0xEA,0xAA,0xAB,
|
||||
0xEA,0xAA,0xAB,0x3A,0x96,0xAC,0x3A,0x69,
|
||||
0xAC,0x0E,0xAA,0xB0,0x0E,0xAA,0xB0,0x0F,
|
||||
0xAA,0xF0,0x3A,0xAA,0xAC,0xEE,0xAA,0xBB,
|
||||
0xEE,0xAA,0xBB,0x33,0xAA,0xCC,0x03,0xAB,
|
||||
0x00,0x00,0xEB,0x00,0x00,0x3F,0xC0,0x00,
|
||||
};
|
||||
|
||||
///// DEFINES
|
||||
|
||||
#define GAME_BASE 0x400
|
||||
#define SCORE_BASE 0x2c00
|
||||
|
||||
#define SPRITE_SHAPE 192 // first sprite shape #
|
||||
#define PLAYER_SHAPE SPRITE_SHAPE
|
||||
#define POWERUP_SHAPE (SPRITE_SHAPE+2)
|
||||
#define OBSTACLE_SHAPE (SPRITE_SHAPE+3)
|
||||
|
||||
#define PLAYER_INDEX 0 // sprite indices
|
||||
#define POWERUP_INDEX 1
|
||||
#define OBSTACLE_INDEX 2
|
||||
|
||||
#define CENTER_X 172 // sprite start X coord.
|
||||
#define FLOOR_Y (128 << 8) // sprite start Y (fixed 8.8)
|
||||
#define JUMP_VELOCITY (-900) // jump velocity (fixed 8.8)
|
||||
#define GRAVITY 32 // gravity (fixed 8.8)
|
||||
|
||||
#define POWERUP_Y 80 // sprite Y of power up
|
||||
#define OBSTACLE_Y 96 // sprite Y of obstacle
|
||||
|
||||
#define SCROLL_TOP 8 // scroll top row
|
||||
#define SCROLL_ROWS 14 // scroll # of rows
|
||||
#define GROUND_ROW 7 // ground row (+ top row)
|
||||
|
||||
///// VARIABLES
|
||||
|
||||
word player_x; // player X
|
||||
word player_y; // player Y (fixed 8.8)
|
||||
signed int player_vel_y; // player Y velocity (fixed 8.8)
|
||||
byte faceleft = 0; // 0 = face right, 1 = face left
|
||||
word scroll_x = 0; // current scroll X position
|
||||
word score = 0; // current player score
|
||||
|
||||
///// FUNCTIONS
|
||||
|
||||
// display list used by rasterirq.h
|
||||
// draws scoreboard and sets scroll register
|
||||
void display_list() {
|
||||
// set x scroll register to scroll value
|
||||
SET_SCROLL_X(scroll_x);
|
||||
// set background color
|
||||
VIC.bgcolor[0] = COLOR_CYAN;
|
||||
// next interrupt is two rows from bottom
|
||||
DLIST_NEXT(248-16);
|
||||
|
||||
// set background color
|
||||
VIC.bgcolor[0] = COLOR_BLUE;
|
||||
// screen memory = 0x2800
|
||||
SET_VIC_SCREEN(SCORE_BASE);
|
||||
// clear x scroll register
|
||||
SET_SCROLL_X(0);
|
||||
// next interrupt is bottom of frame
|
||||
DLIST_NEXT(250);
|
||||
|
||||
// reset screen to 0x400
|
||||
SET_VIC_SCREEN(0x400);
|
||||
// next interrupt is above top of next frame
|
||||
DLIST_RESTART(40);
|
||||
}
|
||||
|
||||
void update_scoreboard() {
|
||||
draw_bcd_word(SCRNADR(SCORE_BASE,7,24), score);
|
||||
}
|
||||
|
||||
void add_score(int delta) {
|
||||
score = bcd_add(score, delta);
|
||||
}
|
||||
|
||||
// clear scoreboard and draw initial strings
|
||||
void init_scoreboard() {
|
||||
memset((void*)SCORE_BASE, ' ', 1024);
|
||||
memcpy((void*)SCRNADR(SCORE_BASE,1,24), "SCORE:", 6);
|
||||
update_scoreboard();
|
||||
}
|
||||
|
||||
void init_sprite_shapes() {
|
||||
sprite_set_shapes(SPRITE_DATA,
|
||||
SPRITE_SHAPE,
|
||||
NUM_SPRITE_PATTERNS);
|
||||
}
|
||||
|
||||
void init_sprite_positions() {
|
||||
// setup sprite positions
|
||||
player_x = CENTER_X;
|
||||
player_y = FLOOR_Y;
|
||||
player_vel_y = 0;
|
||||
sprshad.spr_color[POWERUP_INDEX] = COLOR_YELLOW;
|
||||
sprshad.spr_color[OBSTACLE_INDEX] = COLOR_GRAY3;
|
||||
}
|
||||
|
||||
void move_player(byte joy) {
|
||||
// move sprite based on joystick
|
||||
if (JOY_LEFT(joy)) {
|
||||
player_x -= 2;
|
||||
faceleft = 1;
|
||||
}
|
||||
if (JOY_RIGHT(joy)) {
|
||||
player_x += 1;
|
||||
faceleft = 0;
|
||||
}
|
||||
if (JOY_BTN_1(joy) && player_y == FLOOR_Y) {
|
||||
player_vel_y = JUMP_VELOCITY;
|
||||
}
|
||||
|
||||
// apply velocity
|
||||
player_y += player_vel_y;
|
||||
// apply gravity
|
||||
player_vel_y += GRAVITY;
|
||||
// stop velocity when falling thru floor
|
||||
if (player_y >= FLOOR_Y) {
|
||||
player_y = FLOOR_Y; // reset Y position
|
||||
player_vel_y = 0; // reset velocity
|
||||
}
|
||||
|
||||
// keep player from moving offscreen
|
||||
if (player_x < 36) player_x = 36;
|
||||
if (player_x > 300) player_x = 300;
|
||||
|
||||
// draw player into sprite shadow buffer
|
||||
sprite_draw(PLAYER_INDEX,
|
||||
player_x,
|
||||
player_y >> 8, // fixed point conversion
|
||||
PLAYER_SHAPE + faceleft);
|
||||
}
|
||||
|
||||
void move_items() {
|
||||
// move in sync with scrolling world
|
||||
// draw powerup
|
||||
sprite_draw(POWERUP_INDEX,
|
||||
((scroll_x*2) & 0x1ff),
|
||||
POWERUP_Y,
|
||||
POWERUP_SHAPE);
|
||||
// draw obstacle
|
||||
sprite_draw(OBSTACLE_INDEX,
|
||||
((scroll_x+256) & 0x1ff),
|
||||
OBSTACLE_Y,
|
||||
OBSTACLE_SHAPE);
|
||||
}
|
||||
|
||||
byte get_char_for_row(byte row) {
|
||||
// ground?
|
||||
if (row >= GROUND_ROW) { return 253; }
|
||||
// obstacle?
|
||||
if (row >= GROUND_ROW-3) {
|
||||
// only show obstacle for certain values of scroll_x
|
||||
if ((scroll_x & 0b1110000) == 0) { return 247; }
|
||||
}
|
||||
// default is the sky (empty space)
|
||||
return 32;
|
||||
}
|
||||
|
||||
void draw_right_column() {
|
||||
// get the top-right corner address of scroll area
|
||||
word addr = SCRNADR(GAME_BASE, 39, SCROLL_TOP);
|
||||
byte row;
|
||||
// draw one character per row
|
||||
for (row=0; row<SCROLL_ROWS; row++) {
|
||||
POKE(addr, get_char_for_row(row));
|
||||
addr += 40;
|
||||
}
|
||||
}
|
||||
|
||||
void scroll_one_column_left() {
|
||||
// copy several rows of screen memory
|
||||
// backwards one byte
|
||||
const word start = SCRNADR(GAME_BASE, 0, SCROLL_TOP);
|
||||
const word nbytes = SCROLL_ROWS*40-1;
|
||||
memcpy((byte*)start, (byte*)start+1, nbytes);
|
||||
// draw the right column of characters
|
||||
draw_right_column();
|
||||
}
|
||||
|
||||
void scroll_one_pixel_left() {
|
||||
// scroll left one pixel
|
||||
scroll_x -= 1;
|
||||
// set scroll register with lower three bits
|
||||
VIC.ctrl2 = (VIC.ctrl2 & ~7) | (scroll_x & 7);
|
||||
// move screen memory if the scroll register
|
||||
// has just gone past 0 and wrapped to 7
|
||||
if ((scroll_x & 7) == 7) {
|
||||
scroll_one_column_left();
|
||||
}
|
||||
}
|
||||
|
||||
void detect_player_collision(byte bgcoll, byte sprcoll) {
|
||||
// did we hit a powerup? (#0 and #1)
|
||||
bool hit_powerup = (sprcoll & 0b011) == 0b011;
|
||||
// did player and obstacle sprite (#0 and #2) collide?
|
||||
bool hit_obstacle = (sprcoll & 0b101) == 0b101;
|
||||
// did player (#0) collide with background?
|
||||
hit_obstacle |= (bgcoll & 0b001) != 0;
|
||||
// did we hit anything bad?
|
||||
if (hit_obstacle) {
|
||||
// make player fall downward and backward
|
||||
player_vel_y = -JUMP_VELOCITY;
|
||||
player_x -= 1;
|
||||
sprshad.spr_color[PLAYER_INDEX] = COLOR_LIGHTRED;
|
||||
SID_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
|
||||
SID_PLAY_TONE(8000);
|
||||
add_score(1);
|
||||
update_scoreboard();
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// clear screen, set background color
|
||||
clrscr();
|
||||
VIC.bgcolor[0] = COLOR_CYAN;
|
||||
VIC.bordercolor = COLOR_BLUE;
|
||||
|
||||
// set vertical scroll = 3, 25 rows
|
||||
VIC.ctrl1 = 0b00011011;
|
||||
// set 38 column mode (for X scrolling)
|
||||
VIC.ctrl2 = 0b00000000;
|
||||
// set uniform color of characters
|
||||
memset(COLOR_RAM, COLOR_WHITE, 1000);
|
||||
|
||||
// install the joystick driver
|
||||
joy_install (joy_static_stddrv);
|
||||
|
||||
// setup sound
|
||||
SID_INIT(8,0);
|
||||
|
||||
// set multicolor sprites and colors in shadow buffer
|
||||
sprite_clear(); // clear shadow buffer
|
||||
sprshad.spr_mcolor = 0b11111111; // all sprites multicolor
|
||||
sprshad.spr_exp_y = 1; // double height
|
||||
|
||||
// set colors
|
||||
sprshad.spr_color[PLAYER_INDEX] = COLOR_GREEN;
|
||||
VIC.spr_mcolor0 = COLOR_GRAY2;
|
||||
VIC.spr_mcolor1 = COLOR_BLACK;
|
||||
|
||||
// setup sprites
|
||||
init_sprite_shapes();
|
||||
init_sprite_positions();
|
||||
|
||||
// setup scoreboard
|
||||
init_scoreboard();
|
||||
|
||||
// setup rasterirq library for scoreboard split
|
||||
DLIST_SETUP(display_list);
|
||||
|
||||
// game loop, repeat forever
|
||||
while (1) {
|
||||
// saved collision flags
|
||||
byte sprcoll, bgcoll;
|
||||
|
||||
// wait for end of frame
|
||||
waitvsync();
|
||||
|
||||
//--- START TIME CRITICAL SECTION
|
||||
// grab and reset collision flags
|
||||
sprcoll = VIC.spr_coll;
|
||||
bgcoll = VIC.spr_bg_coll;
|
||||
|
||||
// update sprite registers from sprite shadow buffer
|
||||
sprite_update(DEFAULT_SCREEN);
|
||||
|
||||
// scroll screen
|
||||
scroll_one_pixel_left();
|
||||
//--- END TIME CRITICAL SECTION
|
||||
|
||||
// use collision flags to see if player collided
|
||||
detect_player_collision(bgcoll, sprcoll);
|
||||
|
||||
// get joystick bits and move player
|
||||
move_player(joy_read(0));
|
||||
|
||||
// move obstacle and powerup sprites
|
||||
move_items();
|
||||
}
|
||||
}
|
55
presets/c64/sidmacros.h
Normal file
55
presets/c64/sidmacros.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
// SID voices are v1, v2, v3
|
||||
|
||||
// wave options flags
|
||||
#define SID_GATE 0x01
|
||||
#define SID_SYNC 0x02
|
||||
#define SID_RINGMOD 0x04
|
||||
#define SID_TESTBIT 0x08
|
||||
#define SID_TRIANGLE 0x10
|
||||
#define SID_SAWTOOTH 0x20
|
||||
#define SID_SQUARE 0x40
|
||||
#define SID_NOISE 0x80
|
||||
|
||||
// Init SID global volume
|
||||
// volume: 0-15
|
||||
// filters: bitmask
|
||||
#define SID_INIT(volume, filters) \
|
||||
SID.amp = (volume) | ((filters)<<4);
|
||||
|
||||
// stop voice
|
||||
#define SID_STOP(voice) \
|
||||
SID.voice.ctrl &= ~SID_GATE;
|
||||
|
||||
// start voice
|
||||
#define SID_START(voice) \
|
||||
SID.voice.ctrl |= SID_GATE;
|
||||
|
||||
// set ADSR envelope
|
||||
#define SID_ADSR(voice,attack,decay,sustain,release) \
|
||||
SID.voice.ad = ((decay)&15) | ((attack)<<4); \
|
||||
SID.voice.sr = ((release)&15) | ((sustain)<<4);
|
||||
|
||||
// set frequency (0 - 65535)
|
||||
#define SID_FREQ(voice,_freq) \
|
||||
SID.voice.freq = (_freq);
|
||||
|
||||
// set pulse width (0 - 4095)
|
||||
#define SID_PULSEWIDTH(voice,_pw) \
|
||||
SID.voice.pw = (_pw);
|
||||
|
||||
// set wave shape and options
|
||||
#define SID_WAVE(voice,options) \
|
||||
SID.voice.ctrl = (SID.voice.ctrl & 1) | (options)
|
||||
|
||||
// play a quick square wave pulse
|
||||
#define SID_PULSE_DECAY(voice, freq) \
|
||||
SID_STOP(voice) \
|
||||
SID_FREQ(voice,freq); \
|
||||
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 SID_PLAY_TONE(freq) \
|
||||
if (!SID.read3) { SID_PULSE_DECAY(v3, (freq)) }
|
BIN
presets/c64/sidmusic1.bin
Normal file
BIN
presets/c64/sidmusic1.bin
Normal file
Binary file not shown.
72
presets/c64/sidplaysfx.ca65
Normal file
72
presets/c64/sidplaysfx.ca65
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
; music and SFX from GoatTracker 2 sample files
|
||||
; http://sourceforge.net/projects/goattracker2
|
||||
|
||||
.segment "DATA"
|
||||
|
||||
_sid_playing: .byte $00
|
||||
|
||||
.segment "SIDFILE"
|
||||
|
||||
.incbin "sidmusic1.bin"
|
||||
|
||||
.segment "LOWCODE"
|
||||
|
||||
.global _sid_init, _sid_update, _sid_sfx
|
||||
.global _sid_start, _sid_stop, _sid_playing
|
||||
|
||||
_sid_init:
|
||||
jmp $1000
|
||||
|
||||
_sid_update:
|
||||
bit _sid_playing
|
||||
bpl @noplay
|
||||
jmp $1003
|
||||
@noplay:
|
||||
rts
|
||||
|
||||
_sid_sfx:
|
||||
tax
|
||||
lda sfxtbllo,x ;Address in A,Y
|
||||
ldy sfxtblhi,x
|
||||
ldx #$0e ;Channel index in X
|
||||
jmp $1006 ;(0, 7 or 14)
|
||||
|
||||
_sid_start:
|
||||
lda #$80
|
||||
bne skipstop
|
||||
_sid_stop:
|
||||
lda #$00
|
||||
sta $d418
|
||||
skipstop:
|
||||
sta _sid_playing
|
||||
rts
|
||||
|
||||
sfxtbllo: .byte <arpeggio2
|
||||
.byte <arpeggio1
|
||||
.byte <gunshot
|
||||
.byte <explosion
|
||||
|
||||
sfxtblhi: .byte >arpeggio2
|
||||
.byte >arpeggio1
|
||||
.byte >gunshot
|
||||
.byte >explosion
|
||||
|
||||
arpeggio2:
|
||||
.byte $00,$89,$04,$A2,$41,$A2,$A2,$A6,$A6,$A6,$40,$A9,$A9,$A9,$A2,$A2
|
||||
.byte $A2,$A6,$A6,$A6,$A9,$A9,$A9,$A2,$A2,$A2,$A6,$A6,$A6,$A9,$A9,$A9
|
||||
.byte $A2,$A2,$A2,$A6,$A6,$A6,$A9,$A9,$A9,$00
|
||||
|
||||
arpeggio1:
|
||||
.byte $0A,$00,$02,$A0,$41,$A0,$A0,$A4,$A4,$A4,$A7,$A7,$A7,$A0,$A0,$A0
|
||||
.byte $A4,$A4,$A4,$A7,$A7,$A7,$A0,$A0,$A0,$A4,$A4,$A4,$A7,$A7,$A7,$A0
|
||||
.byte $A0,$A0,$A4,$A4,$A4,$A7,$A7,$A7,$00
|
||||
|
||||
gunshot:
|
||||
.byte $00,$F9,$08,$C4,$81,$A8,$41,$C0,$81,$BE,$BC,$80,$BA,$B8,$B6,$B4
|
||||
.byte $B2,$B0,$AE,$AC,$AA,$A8,$A6,$A4,$A2,$A0,$9E,$9C,$9A,$98,$96,$94
|
||||
.byte $92,$90,$00
|
||||
|
||||
explosion:
|
||||
.byte $00,$FA,$08,$B8,$81,$A4,$41,$A0,$B4,$81,$98,$92,$9C,$90,$95,$9E
|
||||
.byte $92,$80,$94,$8F,$8E,$8D,$8C,$8B,$8A,$89,$88,$87,$86,$84,$00
|
7
presets/c64/sidplaysfx.h
Normal file
7
presets/c64/sidplaysfx.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
extern void sid_init(char musicindex);
|
||||
extern void sid_update(void);
|
||||
extern void sid_sfx(char sfxindex);
|
||||
|
||||
extern void sid_start(void);
|
||||
extern void sid_stop(void);
|
|
@ -3,33 +3,20 @@ Text-based version of a Blockade-style game.
|
|||
For more information, see "Making Arcade Games in C".
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <joystick.h>
|
||||
#include <conio.h>
|
||||
#include <c64.h>
|
||||
#include <cbm_petscii_charmap.h>
|
||||
#include <peekpoke.h>
|
||||
|
||||
#define COLS 40
|
||||
#define ROWS 24
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
#include "common.h"
|
||||
|
||||
// BASL = text address of cursor position
|
||||
static byte** BASL = (byte**) 0xD1;
|
||||
|
||||
byte getchar(byte x, byte y) {
|
||||
// get the character at a specfic x/y position
|
||||
byte readcharxy(byte x, byte y) {
|
||||
gotoxy(x,y); // set cursor position
|
||||
return (*BASL)[x]; // lookup value @ cursor address
|
||||
}
|
||||
|
||||
void delay(byte count) {
|
||||
while (count--) {
|
||||
word i;
|
||||
for (i=0; i<200; i++) ;
|
||||
waitvsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +102,7 @@ void move_player(Player* p) {
|
|||
cputcxy(p->x, p->y, p->tail_attr);
|
||||
p->x += DIR_X[p->dir];
|
||||
p->y += DIR_Y[p->dir];
|
||||
if ((getchar(p->x, p->y) & 0x7f) != ' ')
|
||||
if ((readcharxy(p->x, p->y) & 0x7f) != ' ')
|
||||
p->collided = 1;
|
||||
draw_player(p);
|
||||
}
|
||||
|
@ -141,7 +128,8 @@ byte ai_try_dir(Player* p, dir_t dir, byte shift) {
|
|||
dir &= 3;
|
||||
x = p->x + (DIR_X[dir] << shift);
|
||||
y = p->y + (DIR_Y[dir] << shift);
|
||||
if (x < COLS && y < ROWS && (getchar(x, y) & 0x7f) == ' ') {
|
||||
if (x < COLS && y < ROWS
|
||||
&& (readcharxy(x, y) & 0x7f) == ' ') {
|
||||
p->dir = dir;
|
||||
return 1;
|
||||
} else {
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <peekpoke.h>
|
||||
#include <string.h>
|
||||
#include <c64.h>
|
||||
#include <cbm_petscii_charmap.h>
|
||||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
void main(void) {
|
||||
clrscr();
|
||||
printf("\r\nHello World!\r\n");
|
||||
printf("\nHello World!\n");
|
||||
getchar();
|
||||
}
|
||||
|
|
121
presets/c64/sprite_collision.c
Normal file
121
presets/c64/sprite_collision.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
/*{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
|
||||
};
|
||||
|
||||
#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];
|
||||
|
||||
void init_sprites(void) {
|
||||
byte i;
|
||||
// setup sprite positions
|
||||
for (i=0; i<8; i++) {
|
||||
xpos[i] = ((i & 3) * 0x2000) - 0x3000;
|
||||
ypos[i] = (i * 0x1000) - 0x3000;
|
||||
sprshad.spr_color[i] = i | 8;
|
||||
}
|
||||
}
|
||||
|
||||
void move_sprites(void) {
|
||||
byte i;
|
||||
for (i=0; i<8; i++) {
|
||||
//VIC.bordercolor = i;
|
||||
sprite_draw(i,
|
||||
(xpos[i] >> 7) + 172,
|
||||
(ypos[i] >> 8) + 145,
|
||||
SPRITE_SHAPE);
|
||||
// update position
|
||||
xpos[i] += xvel[i];
|
||||
ypos[i] += yvel[i];
|
||||
}
|
||||
}
|
||||
|
||||
void update_sprites(void) {
|
||||
byte i;
|
||||
for (i=0; i<8; i++) {
|
||||
// update velocity
|
||||
xvel[i] -= xpos[i] >> 12;
|
||||
yvel[i] -= ypos[i] >> 12;
|
||||
}
|
||||
}
|
||||
|
||||
void collide_sprites(byte spr_coll) {
|
||||
byte i;
|
||||
byte mask = 1;
|
||||
// exit if no collisions
|
||||
if (!spr_coll) return;
|
||||
// iterate all sprites that have their flag set
|
||||
for (i=0; i<8; i++, mask<<=1) {
|
||||
//VIC.bordercolor = i;
|
||||
if (spr_coll & mask) {
|
||||
// find the first sprite that intersects
|
||||
byte j = sprite_get_closest_collision(i, spr_coll);
|
||||
// returns 0..7 if a sprite was found
|
||||
if (j < 8) {
|
||||
xvel[i] = (xpos[i] - xpos[j]) >> 4;
|
||||
yvel[i] = (ypos[i] - ypos[j]) >> 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iterate_game(void) {
|
||||
byte spr_coll;
|
||||
|
||||
// wait for vblank
|
||||
waitvsync();
|
||||
// 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
|
||||
move_sprites();
|
||||
// and update velocity and position
|
||||
update_sprites();
|
||||
// if any flags are set in the collision register,
|
||||
// process sprite collisions
|
||||
collide_sprites(spr_coll);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
clrscr();
|
||||
VIC.bordercolor = 0;
|
||||
|
||||
// setup sprite library and copy sprite to VIC bank
|
||||
sprite_clear();
|
||||
sprite_set_shapes(SPRITEMC, SPRITE_SHAPE, 1);
|
||||
|
||||
// set colors
|
||||
sprshad.spr_mcolor = 0xff;
|
||||
VIC.spr_mcolor0 = 4;
|
||||
VIC.spr_mcolor1 = 7;
|
||||
|
||||
// set sprite initial positions
|
||||
init_sprites();
|
||||
|
||||
// game loop
|
||||
while (1) {
|
||||
iterate_game();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,26 +4,33 @@
|
|||
|
||||
SpriteShadow sprshad;
|
||||
|
||||
void sprite_update(char* vicbank) {
|
||||
memcpy(vicbank + 0x3f8, sprshad.spr_shapes, 8);
|
||||
VIC.spr_ena = sprshad.spr_ena;
|
||||
VIC.spr_hi_x = sprshad.spr_hi_x;
|
||||
void sprite_clear(void) {
|
||||
memset(&sprshad, 0, sizeof(sprshad));
|
||||
}
|
||||
|
||||
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);
|
||||
VIC.spr_ena = sprshad.spr_ena;
|
||||
VIC.spr_hi_x = sprshad.spr_hi_x;
|
||||
VIC.spr_exp_x = sprshad.spr_exp_x;
|
||||
VIC.spr_exp_y = sprshad.spr_exp_y;
|
||||
VIC.spr_bg_prio = sprshad.spr_bg_prio;
|
||||
VIC.spr_mcolor = sprshad.spr_mcolor;
|
||||
VIC.spr_mcolor0 = sprshad.spr_mcolor0;
|
||||
VIC.spr_mcolor1 = sprshad.spr_mcolor1;
|
||||
}
|
||||
|
||||
void sprite_shape(char* vicbank, byte index, const char* sprite_data) {
|
||||
memcpy(vicbank + index*64, sprite_data, 64);
|
||||
void sprite_set_shapes(const void* sprite_data,
|
||||
byte index,
|
||||
byte count)
|
||||
{
|
||||
memcpy(get_vic_bank_start() + index * 64,
|
||||
sprite_data,
|
||||
64 * count);
|
||||
}
|
||||
|
||||
const byte BITS[8] = {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
||||
};
|
||||
|
||||
void sprite_draw(byte i, word x, byte y, byte shape) {
|
||||
|
@ -38,7 +45,25 @@ void sprite_draw(byte i, word x, byte y, byte shape) {
|
|||
sprshad.spr_shapes[i] = shape;
|
||||
}
|
||||
|
||||
void sprite_clear(void) {
|
||||
sprshad.spr_ena = 0;
|
||||
byte sprite_get_closest_collision(byte i, byte spr_coll) {
|
||||
byte j;
|
||||
byte jmask = 1;
|
||||
byte dx,dy;
|
||||
if (spr_coll & BITS[i]) {
|
||||
spr_coll ^= BITS[i];
|
||||
for (j=0; j<8; j++, jmask<<=1) {
|
||||
if (spr_coll & jmask) {
|
||||
// TODO?
|
||||
dx = sprshad.spr_pos[i].x - sprshad.spr_pos[j].x + 24;
|
||||
if (dx < 48) {
|
||||
dy = sprshad.spr_pos[i].y - sprshad.spr_pos[j].y + 21;
|
||||
if (dy < 42) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,28 +3,40 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
byte spr_ena; /* Enable sprites */
|
||||
byte spr_hi_x; /* High bits of X coordinate */
|
||||
byte spr_exp_x; /* Expand sprites in X dir */
|
||||
byte spr_exp_y; /* Expand sprites in Y dir */
|
||||
byte spr_bg_prio; /* Priority to background */
|
||||
byte spr_mcolor; /* Sprite multicolor bits */
|
||||
byte spr_mcolor0; /* Color 0 for multicolor sprites */
|
||||
byte spr_mcolor1; /* Color 1 for multicolor sprites */
|
||||
byte spr_color[8]; /* Colors for the sprites */
|
||||
typedef struct SpriteShadow {
|
||||
struct {
|
||||
byte x; /* X coordinate */
|
||||
byte y; /* Y coordinate */
|
||||
} spr_pos[8];
|
||||
byte spr_hi_x; /* High bits of X coordinate */
|
||||
byte spr_ena; /* Enable sprites */
|
||||
byte spr_exp_y; /* Expand sprites in Y dir */
|
||||
byte spr_bg_prio; /* Priority to background */
|
||||
byte spr_mcolor; /* Sprite multicolor bits */
|
||||
byte spr_exp_x; /* Expand sprites in X dir */
|
||||
byte spr_color[8]; /* Colors for the sprites */
|
||||
byte spr_shapes[8]; /* sprite shapes */
|
||||
} SpriteShadow;
|
||||
|
||||
/* sprite shadow buffer */
|
||||
extern SpriteShadow sprshad;
|
||||
|
||||
void sprite_update(char* screenram);
|
||||
void sprite_shape(char* vicbank, byte index, const char* sprite_data);
|
||||
void sprite_draw(byte i, word x, byte y, byte shape);
|
||||
void sprite_clear(void);
|
||||
/* 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
|
||||
|
|
75
presets/c64/spritesinborder.c
Normal file
75
presets/c64/spritesinborder.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
|
||||
//#link "common.c"
|
||||
#include "common.h"
|
||||
|
||||
//#link "rasterirq.ca65"
|
||||
#include "rasterirq.h"
|
||||
|
||||
//#link "sprites.c"
|
||||
#include "sprites.h"
|
||||
|
||||
#include <cbm_petscii_charmap.h>
|
||||
|
||||
/*{w:24,h:21,bpp:1,brev:1}*/
|
||||
const char spriteshape[3*21] = {
|
||||
0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xE0,
|
||||
0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0,
|
||||
0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0,
|
||||
0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40,
|
||||
0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80,
|
||||
0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00,
|
||||
0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00
|
||||
};
|
||||
|
||||
byte scroll_x = 0;
|
||||
|
||||
void dlist_example(void) {
|
||||
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;
|
||||
VIC.bordercolor = 4;
|
||||
DLIST_RESTART(30);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
byte i;
|
||||
|
||||
clrscr();
|
||||
|
||||
sprite_clear();
|
||||
sprite_set_shapes(spriteshape, 192, 1);
|
||||
|
||||
// set colors
|
||||
sprshad.spr_exp_x = 0xff;
|
||||
for (i=0; i<8; i++) {
|
||||
sprshad.spr_color[i] = i+3;
|
||||
sprite_draw(i, i*38+24, 248, 192);
|
||||
}
|
||||
// TODO: can't do in IRQ
|
||||
|
||||
DLIST_SETUP(dlist_example);
|
||||
while (1) {
|
||||
waitvsync();
|
||||
sprite_update(DEFAULT_SCREEN);
|
||||
printf("Raster IRQ-driven display list! ");
|
||||
}
|
||||
}
|
136
presets/c64/test_multiplex.c
Normal file
136
presets/c64/test_multiplex.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "sprites.h"
|
||||
//#link "sprites.c"
|
||||
|
||||
#define NUM_SPRITE_PATTERNS 2
|
||||
#define SPRITE_SHAPE 192
|
||||
#define SPRITES_PER_ROW 6
|
||||
|
||||
/*{w:12,h:21,bpp:2,brev:1,count:2}*/
|
||||
const char SPRITEMC[64*NUM_SPRITE_PATTERNS] = {
|
||||
0x00,0xAA,0x80,0x02,0xAA,0xA0,0x0A,0xAA,0xA8,
|
||||
0x0A,0xAE,0xA8,0x0A,0xBB,0xA8,0x0A,0xBA,0xA8,
|
||||
0x0A,0xBB,0xA8,0x0A,0xAE,0xA8,0x0A,0xAA,0xA8,
|
||||
0x09,0xAA,0x98,0x08,0x6A,0x48,0x08,0x1D,0x08,
|
||||
0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20,
|
||||
0x00,0x8C,0x80,0x00,0x8C,0x80,0x00,0x55,0x40,
|
||||
0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00,
|
||||
0,
|
||||
0x00,0xAE,0x80,0x02,0xBF,0xA0,0x0B,0xBF,0xB8,
|
||||
0x0B,0xBF,0xB8,0x0B,0xBF,0xB8,0x0B,0xBF,0xB8,
|
||||
0x0B,0xBF,0xB8,0x0B,0xBF,0xB8,0x0B,0xAE,0xB8,
|
||||
0x09,0xAE,0x98,0x08,0x6E,0x48,0x08,0x1D,0x08,
|
||||
0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20,
|
||||
0x08,0x8C,0x88,0x08,0x8C,0x88,0x20,0x55,0x42,
|
||||
0x20,0x77,0x42,0x20,0x5D,0x42,0x20,0x15,0x02,
|
||||
0,
|
||||
};
|
||||
|
||||
SpriteShadow* sprite_rows[3]; // row sprite buffers
|
||||
int player_x = 172; // player X coordinate
|
||||
byte player_y = 222; // player Y coordinate
|
||||
|
||||
void init_sprites(void) {
|
||||
byte row,i;
|
||||
// iterate through each row of sprites
|
||||
for (row=0; row<3; row++) {
|
||||
// fill in data for local sprite buffer
|
||||
sprite_clear();
|
||||
sprshad.spr_mcolor = 0xff;
|
||||
for (i=0; i<SPRITES_PER_ROW; i++) {
|
||||
sprite_draw(i, i*50+50, row*50+60, SPRITE_SHAPE);
|
||||
sprshad.spr_color[i] = (i+row)|8;
|
||||
}
|
||||
// allocate sprite buffer for row
|
||||
sprite_rows[row] = (SpriteShadow*) malloc(sizeof(SpriteShadow));
|
||||
// and copy local buffer into it
|
||||
*sprite_rows[row] = sprshad;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_sprite_row(byte row, byte rasterline) {
|
||||
// copy sprite row data to sprite shadow buffer
|
||||
sprshad = *sprite_rows[row];
|
||||
// player is part of row 2, draw player?
|
||||
if (row == 2) {
|
||||
sprite_draw(7, player_x, player_y, SPRITE_SHAPE+1);
|
||||
sprshad.spr_color[7] = 15;
|
||||
}
|
||||
// wait for the raster line
|
||||
raster_wait(rasterline);
|
||||
// then update sprite registers from shadow buffer
|
||||
VIC.bordercolor = row+1; // (so we see the timing)
|
||||
sprite_update(DEFAULT_SCREEN);
|
||||
VIC.bordercolor = 0;
|
||||
}
|
||||
|
||||
void move_sprite_x(SpriteShadow* spr,
|
||||
byte index,
|
||||
sbyte delta_x)
|
||||
{
|
||||
word x = spr->spr_pos[index].x;
|
||||
byte mask = BITS[index]; // lookup table for (1 << index)
|
||||
if (spr->spr_hi_x & mask) {
|
||||
x |= 0x100;
|
||||
}
|
||||
x += delta_x;
|
||||
spr->spr_pos[index].x = x;
|
||||
if (x & 0x100) {
|
||||
spr->spr_hi_x |= mask;
|
||||
} else {
|
||||
spr->spr_hi_x &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
void move_sprites() {
|
||||
byte i;
|
||||
for (i=0; i<SPRITES_PER_ROW; i++) {
|
||||
move_sprite_x(sprite_rows[0], i, 3);
|
||||
move_sprite_x(sprite_rows[1], i, -2);
|
||||
}
|
||||
}
|
||||
|
||||
void move_player() {
|
||||
byte joy = PEEK(0xdc01); // read joystick #0
|
||||
if (joy & 0x8) { player_x -= 1; } // left
|
||||
if (joy & 0x4) { player_x += 1; } // right
|
||||
}
|
||||
|
||||
void iterate_game(void) {
|
||||
waitvsync();
|
||||
draw_sprite_row(0, 1);
|
||||
draw_sprite_row(1, 60+21);
|
||||
draw_sprite_row(2, 110+21);
|
||||
move_sprites();
|
||||
move_player();
|
||||
VIC.bordercolor = 9;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
VIC.bordercolor = 0;
|
||||
clrscr();
|
||||
|
||||
// setup sprite library and copy sprite to VIC bank
|
||||
sprite_clear();
|
||||
sprite_set_shapes(SPRITEMC, SPRITE_SHAPE, NUM_SPRITE_PATTERNS);
|
||||
|
||||
// set colors
|
||||
VIC.spr_mcolor0 = 4;
|
||||
VIC.spr_mcolor1 = 7;
|
||||
|
||||
// set sprite initial positions
|
||||
init_sprites();
|
||||
|
||||
// turn off interrupts so we don't mess up timing
|
||||
asm("sei");
|
||||
|
||||
// game loop
|
||||
while (1) {
|
||||
iterate_game();
|
||||
}
|
||||
}
|
||||
|
135
presets/c64/test_multispritelib.c
Normal file
135
presets/c64/test_multispritelib.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#include "multisprite.h"
|
||||
//#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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// constants for display list
|
||||
|
||||
#define Y0 21
|
||||
#define Y1 35
|
||||
#define YS 42
|
||||
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
149
presets/c64/testmultispritelib.c
Normal file
149
presets/c64/testmultispritelib.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
//#link "multisprite.ca65"
|
||||
|
||||
#include "rasterirq.h"
|
||||
//#link "rasterirq.ca65"
|
||||
|
||||
#define NUM_TEST_SPRITES 24
|
||||
|
||||
byte* sprite_bank = (byte*)DEFAULT_SCREEN + 0x3f8;
|
||||
|
||||
/*{w:12,h:21,bpp:2,brev:1}*/
|
||||
const char SPRITEMC[3*21] = {
|
||||
0x00,0xAA,0x80,0x02,0xAA,0xA0,0x0A,0xAA,0xA8,
|
||||
0x0A,0xAE,0xA8,0x0A,0xBB,0xA8,0x0A,0xBA,0xA8,
|
||||
0x0A,0xBB,0xA8,0x0A,0xAE,0xA8,0x0A,0xAA,0xA8,
|
||||
0x09,0xAA,0x98,0x08,0x6A,0x48,0x08,0x1D,0x08,
|
||||
0x02,0x0C,0x20,0x02,0x0C,0x20,0x02,0x0C,0x20,
|
||||
0x00,0x8C,0x80,0x00,0x8C,0x80,0x00,0x55,0x40,
|
||||
0x00,0x77,0x40,0x00,0x5D,0x40,0x00,0x15,0x00
|
||||
};
|
||||
|
||||
/*
|
||||
const byte BITS[8] = {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
||||
};
|
||||
const byte NOTBITS[8] = {
|
||||
~0x01, ~0x02, ~0x04, ~0x08, ~0x10, ~0x20, ~0x40, ~0x80
|
||||
};
|
||||
|
||||
typedef struct MSpriteFlags {
|
||||
byte xhi:1;
|
||||
byte exp_x:1;
|
||||
byte exp_y:1;
|
||||
byte mcolor:1;
|
||||
byte bgprio:1;
|
||||
} MSpriteFlags;
|
||||
*/
|
||||
|
||||
#include "multisprite.h"
|
||||
|
||||
void sprite_shape(char* vicbank, byte index, const char* sprite_data) {
|
||||
memmove(vicbank + index*64, sprite_data, 64);
|
||||
}
|
||||
|
||||
void setup_sprites() {
|
||||
byte i;
|
||||
sprite_shape((void*)0x0, 255, SPRITEMC);
|
||||
for (i=0; i<MAX_MSPRITES; i++) {
|
||||
msprite_order[i] = i;
|
||||
msprite_y[i] = 255;
|
||||
}
|
||||
for (i=0; i<NUM_TEST_SPRITES; i++) {
|
||||
int x = i*13+20;
|
||||
msprite_x_lo[i] = x;
|
||||
msprite_x_hi[i] = x>>8;
|
||||
msprite_y[i] = i*0+50;
|
||||
// msprite_flags[i] = 0;
|
||||
msprite_shape[i] = 255;
|
||||
msprite_color[i] = i|8;
|
||||
}
|
||||
}
|
||||
|
||||
void display_list() {
|
||||
msprite_render_init();
|
||||
msprite_render_section();
|
||||
DLIST_NEXT(Y1+YS*1);
|
||||
msprite_render_section();
|
||||
DLIST_NEXT(Y1+YS*2);
|
||||
msprite_render_section();
|
||||
DLIST_NEXT(Y1+YS*3);
|
||||
msprite_render_section();
|
||||
DLIST_NEXT(Y1+YS*4);
|
||||
msprite_render_section();
|
||||
DLIST_NEXT(Y1+YS*5);
|
||||
msprite_render_section();
|
||||
VIC.bordercolor = 3;
|
||||
msprite_sort();
|
||||
VIC.bordercolor = 4;
|
||||
msprite_add_velocity(NUM_TEST_SPRITES);
|
||||
VIC.bordercolor = 0;
|
||||
DLIST_RESTART(Y0);
|
||||
}
|
||||
|
||||
void msprite_set_position(byte index, int x, byte y) {
|
||||
asm("sei");
|
||||
msprite_x_lo[index] = x;
|
||||
msprite_x_hi[index] = x >> 8;
|
||||
msprite_y[index] = y;
|
||||
asm("cli");
|
||||
}
|
||||
|
||||
void msprite_add_position(byte index, byte dx, byte dy) {
|
||||
int x;
|
||||
x = msprite_x_lo[index] | msprite_x_hi[index]*256;
|
||||
x += dx;
|
||||
asm("sei");
|
||||
msprite_x_lo[index] = x;
|
||||
msprite_x_hi[index] = x >> 8;
|
||||
msprite_y[index] += dy;
|
||||
asm("cli");
|
||||
}
|
||||
|
||||
void apply_gravity() {
|
||||
byte i;
|
||||
for (i=0; i<NUM_TEST_SPRITES; i++) {
|
||||
int xvel = msprite_xvel_lo[i] + msprite_xvel_hi[i]*256;
|
||||
int yvel = msprite_yvel_lo[i] + msprite_yvel_hi[i]*256;
|
||||
int xpos = msprite_x_lo[i] + msprite_x_hi[i]*256;
|
||||
int ypos = msprite_y[i];
|
||||
xpos -= 172;
|
||||
ypos -= 145;
|
||||
xvel -= xpos / 8;
|
||||
yvel -= ypos / 8;
|
||||
msprite_xvel_lo[i] = xvel;
|
||||
msprite_xvel_hi[i] = xvel >> 8;
|
||||
msprite_yvel_lo[i] = yvel;
|
||||
msprite_yvel_hi[i] = yvel >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
void do_test() {
|
||||
byte i;
|
||||
raster_wait(160);
|
||||
for (i=0; i<NUM_TEST_SPRITES; i++) {
|
||||
msprite_yvel_lo[i] = i*8;
|
||||
//msprite_add_position(i,i&3,i&3);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
clrscr();
|
||||
|
||||
setup_sprites();
|
||||
|
||||
// set colors
|
||||
VIC.spr_mcolor = 0xff;
|
||||
VIC.spr_mcolor0 = 4;
|
||||
VIC.spr_mcolor1 = 7;
|
||||
|
||||
DLIST_SETUP(display_list);
|
||||
|
||||
while (1) {
|
||||
do_test();
|
||||
}
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
// ported from
|
||||
// https://odensskjegg.home.blog/2018/12/29/recreating-the-commodore-64-user-guide-code-samples-in-cc65-part-three-sprites/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <peekpoke.h>
|
||||
#include <c64.h>
|
||||
#include "common.h"
|
||||
|
||||
/*{w:24,h:21,bpp:1,brev:1}*/
|
||||
const char sprite[3*21] = {
|
||||
|
|
72
presets/c64/viewer-badspacerobots-c64.multi.asm
Normal file
72
presets/c64/viewer-badspacerobots-c64.multi.asm
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
processor 6502
|
||||
include "basicheader.dasm"
|
||||
|
||||
Src equ $02
|
||||
Dest equ $04
|
||||
|
||||
Start:
|
||||
lda #$38 ; 25 rows, on, bitmap
|
||||
sta $d011 ; VIC control #1
|
||||
lda #$18 ; 40 column, multicolor
|
||||
sta $d016 ; VIC control #2
|
||||
lda #$02
|
||||
sta $dd00 ; set VIC bank ($4000-$7FFF)
|
||||
lda #$80
|
||||
sta $d018 ; set VIC screen to $6000
|
||||
lda XtraData+0
|
||||
sta $d020 ; border
|
||||
sta $d021 ; background
|
||||
lda #0
|
||||
sta Dest
|
||||
; copy char memory
|
||||
lda #<CharData
|
||||
sta Src
|
||||
lda #>CharData
|
||||
sta Src+1
|
||||
lda #$40
|
||||
sta Dest+1
|
||||
ldx #$20
|
||||
jsr CopyMem
|
||||
; copy screen memory
|
||||
lda #<ScreenData
|
||||
sta Src
|
||||
lda #>ScreenData
|
||||
sta Src+1
|
||||
lda #$60
|
||||
sta Dest+1
|
||||
ldx #$04
|
||||
jsr CopyMem
|
||||
; copy color RAM
|
||||
lda #<ColorData
|
||||
sta Src
|
||||
lda #>ColorData
|
||||
sta Src+1
|
||||
lda #$d8
|
||||
sta Dest+1
|
||||
ldx #4
|
||||
jsr CopyMem
|
||||
; infinite loop
|
||||
jmp .
|
||||
|
||||
; copy data from Src to Dest
|
||||
; X = number of bytes * 256
|
||||
CopyMem
|
||||
ldy #0
|
||||
.Loop
|
||||
lda (Src),y
|
||||
sta (Dest),y
|
||||
iny
|
||||
bne .Loop
|
||||
inc Src+1
|
||||
inc Dest+1
|
||||
dex
|
||||
bne .Loop
|
||||
rts
|
||||
|
||||
; bitmap data
|
||||
CharData equ .
|
||||
ScreenData equ CharData+8000
|
||||
ColorData equ ScreenData+1000
|
||||
XtraData equ ColorData+1000
|
||||
incbin "badspacerobots-c64.multi.bin"
|
BIN
res/c64.bios
BIN
res/c64.bios
Binary file not shown.
BIN
res/c64.wasm
BIN
res/c64.wasm
Binary file not shown.
BIN
res/cpc.wasm
BIN
res/cpc.wasm
Binary file not shown.
BIN
res/zx.wasm
BIN
res/zx.wasm
Binary file not shown.
|
@ -894,21 +894,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();
|
||||
}
|
||||
|
|
|
@ -53,7 +53,9 @@ export enum KeyFlags {
|
|||
export function _setKeyboardEvents(canvas:HTMLElement, callback:KeyboardCallback) {
|
||||
canvas.onkeydown = (e) => {
|
||||
callback(e.which, 0, KeyFlags.KeyDown|_metakeyflags(e));
|
||||
if (e.ctrlKey || e.which == 8 || e.which == 9 || e.which == 27) { // eat backspace, tab, escape keys
|
||||
// eat backspace, tab, escape, slash, ' keys
|
||||
if (e.ctrlKey || e.which == 8 || e.which == 9 || e.which == 27
|
||||
|| e.which == 191 || e.which == 191 || e.which == 222) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@ export class SourceFile {
|
|||
}
|
||||
}
|
||||
// TODO: smarter about looking for source lines between two addresses
|
||||
findLineForOffset(PC:number, lookbehind:number) {
|
||||
findLineForOffset(PC:number, lookbehind:number) : SourceLine {
|
||||
if (this.offset2loc) {
|
||||
for (var i=0; i<=lookbehind; i++) {
|
||||
var loc = this.offset2loc[PC];
|
||||
|
|
|
@ -27,22 +27,23 @@ export type SelectableTilemap = {
|
|||
}
|
||||
|
||||
export type PixelEditorImageFormat = {
|
||||
w:number
|
||||
h:number
|
||||
count?:number
|
||||
bpp?:number
|
||||
np?:number
|
||||
bpw?:number
|
||||
sl?:number
|
||||
pofs?:number
|
||||
remap?:number[]
|
||||
reindex?:number[]
|
||||
brev?:boolean
|
||||
flip?:boolean
|
||||
w:number // width
|
||||
h:number // height
|
||||
count?:number // # of images
|
||||
bpp?:number // bits per pixel
|
||||
np?:number // number of planes
|
||||
bpw?:number // bits per word
|
||||
sl?:number // words per line
|
||||
pofs?:number // plane offset
|
||||
remap?:number[] // remap array
|
||||
reindex?:number[] // reindex array
|
||||
brev?:boolean // bit reverse (msb is leftmost)
|
||||
flip?:boolean // flip vertically
|
||||
skip?:number // skip bytes
|
||||
wpimg?:number // words per image
|
||||
aspect?:number // aspect ratio
|
||||
xform?:string // CSS transform
|
||||
destfmt?:PixelEditorImageFormat
|
||||
xform?:string
|
||||
skip?:number
|
||||
aspect?:number
|
||||
};
|
||||
|
||||
export type PixelEditorPaletteFormat = {
|
||||
|
@ -162,12 +163,13 @@ export function convertWordsToImages(words:UintArray, fmt:PixelEditorImageFormat
|
|||
var mask = (1 << bpp)-1;
|
||||
var pofs = fmt.pofs || wordsperline*height*count;
|
||||
var skip = fmt.skip || 0;
|
||||
var wpimg = fmt.wpimg || wordsperline*height;
|
||||
var images = [];
|
||||
for (var n=0; n<count; n++) {
|
||||
var imgdata = [];
|
||||
for (var y=0; y<height; y++) {
|
||||
var yp = fmt.flip ? height-1-y : y;
|
||||
var ofs0 = n*wordsperline*height + yp*wordsperline;
|
||||
var ofs0 = wpimg*n + yp*wordsperline;
|
||||
var shift = 0;
|
||||
for (var x=0; x<width; x++) {
|
||||
var color = 0;
|
||||
|
@ -202,19 +204,22 @@ export function convertImagesToWords(images:Uint8Array[], fmt:PixelEditorImageFo
|
|||
var mask = (1 << bpp)-1;
|
||||
var pofs = fmt.pofs || wordsperline*height*count;
|
||||
var skip = fmt.skip || 0;
|
||||
var wpimg = fmt.wpimg || wordsperline*height;
|
||||
|
||||
var words;
|
||||
if (nplanes > 0 && fmt.sl) // TODO?
|
||||
words = new Uint8Array(wordsperline*height*count);
|
||||
words = new Uint8Array(wpimg*count);
|
||||
else if (bitsperword <= 8)
|
||||
words = new Uint8Array(wordsperline*height*count*nplanes);
|
||||
words = new Uint8Array(wpimg*count*nplanes);
|
||||
else
|
||||
words = new Uint32Array(wordsperline*height*count*nplanes);
|
||||
words = new Uint32Array(wpimg*count*nplanes);
|
||||
|
||||
for (var n=0; n<count; n++) {
|
||||
var imgdata = images[n];
|
||||
var i = 0;
|
||||
for (var y=0; y<height; y++) {
|
||||
var yp = fmt.flip ? height-1-y : y;
|
||||
var ofs0 = n*wordsperline*height + yp*wordsperline;
|
||||
var ofs0 = n*wpimg + yp*wordsperline;
|
||||
var shift = 0;
|
||||
for (var x=0; x<width; x++) {
|
||||
var color = imgdata[i++];
|
||||
|
@ -455,7 +460,7 @@ export class TextDataNode extends CodeProjectDataNode {
|
|||
}
|
||||
updateLeft() {
|
||||
if (this.right.words.length != this.words.length)
|
||||
throw Error("Expected " + this.right.words.length + " bytes; image has " + this.words.length);
|
||||
throw Error("Cannot put " + this.right.words.length + " image bytes into array of " + this.words.length + " bytes");
|
||||
this.words = this.right.words;
|
||||
// TODO: reload editors?
|
||||
var datastr = this.text.substring(this.start, this.end);
|
||||
|
@ -1072,7 +1077,12 @@ class PixEditor extends Viewer {
|
|||
|
||||
commit() {
|
||||
this.updateImage();
|
||||
try {
|
||||
this.left.refreshLeft();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
alert(`Could not update source code. ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
remapPixels(mapfn : (x:number,y:number) => number) {
|
||||
|
|
|
@ -14,8 +14,8 @@ import { StateRecorderImpl } from "../common/recorder";
|
|||
import { GHSession, GithubService, getRepos, parseGithubURL } from "./services";
|
||||
import Split = require('split.js');
|
||||
import { importPlatform } from "../platform/_index";
|
||||
import { DisassemblerView, ListingView, SourceEditor } from "./views/editors";
|
||||
import { AddressHeatMapView, BinaryFileView, MemoryMapView, MemoryView, ProbeLogView, ProbeSymbolView, RasterPCHeatMapView, ScanlineIOView, VRAMMemoryView } from "./views/debugviews";
|
||||
import { DisassemblerView, ListingView, PC_LINE_LOOKAHEAD, SourceEditor } from "./views/editors";
|
||||
import { AddressHeatMapView, BinaryFileView, MemoryMapView, MemoryView, ProbeLogView, ProbeSymbolView, RasterPCHeatMapView, RasterStackMapView, ScanlineIOView, VRAMMemoryView } from "./views/debugviews";
|
||||
import { AssetEditorView } from "./views/asseteditor";
|
||||
import { isMobileDevice } from "./views/baseviews";
|
||||
import { CallStackView, DebugBrowserView } from "./views/treeviews";
|
||||
|
@ -80,11 +80,16 @@ var store : LocalForage; // persistent store
|
|||
export var compparams; // received build params from worker
|
||||
export var lastDebugState : EmuState; // last debug state (object)
|
||||
|
||||
type DebugCommandType = null
|
||||
| 'toline' | 'step' | 'stepout' | 'stepover'
|
||||
| 'tovsync' | 'stepback' | 'restart';
|
||||
|
||||
var lastDebugInfo; // last debug info (CPU text)
|
||||
var debugCategory; // current debug category
|
||||
var debugTickPaused = false;
|
||||
var recorderActive = false;
|
||||
var lastViewClicked = null;
|
||||
var lastViewClicked : string = null;
|
||||
var lastDebugCommand : DebugCommandType = null;
|
||||
var errorWasRuntime = false;
|
||||
var lastBreakExpr = "c.PC == 0x6000";
|
||||
|
||||
|
@ -360,7 +365,8 @@ function refreshWindowList() {
|
|||
});
|
||||
// TODO: only if raster
|
||||
addWindowItem("#crtheatmap", "CRT Probe", () => {
|
||||
return new RasterPCHeatMapView();
|
||||
//return new RasterPCHeatMapView();
|
||||
return new RasterStackMapView();
|
||||
});
|
||||
addWindowItem("#probelog", "Probe Log", () => {
|
||||
return new ProbeLogView();
|
||||
|
@ -1425,30 +1431,40 @@ function checkRunReady() {
|
|||
}
|
||||
|
||||
function openRelevantListing(state: EmuState) {
|
||||
// if we clicked on another window, retain it
|
||||
if (lastViewClicked != null) return;
|
||||
// if we clicked on a specific tool, don't switch windows
|
||||
if (lastViewClicked && lastViewClicked.startsWith('#')) return;
|
||||
// don't switch windows for specific debug commands
|
||||
if (['toline','restart','tovsync','stepover'].includes(lastDebugCommand)) return;
|
||||
// has to support disassembly, at least
|
||||
if (!platform.disassemble) return;
|
||||
// search through listings
|
||||
var listings = current_project.getListings();
|
||||
var bestid = "#disasm";
|
||||
var bestscore = 32;
|
||||
let listings = current_project.getListings();
|
||||
let bestid = "#disasm";
|
||||
let bestscore = 256;
|
||||
if (listings) {
|
||||
var pc = state.c ? (state.c.EPC || state.c.PC) : 0;
|
||||
for (var lstfn in listings) {
|
||||
var lst = listings[lstfn];
|
||||
var file = lst.assemblyfile || lst.sourcefile;
|
||||
let pc = state.c ? (state.c.EPC || state.c.PC) : 0;
|
||||
for (let lstfn in listings) {
|
||||
let lst = listings[lstfn];
|
||||
let file = lst.assemblyfile || lst.sourcefile;
|
||||
// pick either listing or source file
|
||||
var wndid = current_project.filename2path[lstfn] || lstfn;
|
||||
let wndid = current_project.filename2path[lstfn] || lstfn;
|
||||
if (file == lst.sourcefile) wndid = projectWindows.findWindowWithFilePrefix(lstfn);
|
||||
// does this window exist?
|
||||
if (projectWindows.isWindow(wndid)) {
|
||||
var res = file && file.findLineForOffset(pc, 32); // TODO: const
|
||||
if (res && pc-res.offset < bestscore) {
|
||||
// find the source line at the PC or closely before it
|
||||
let srcline1 = file && file.findLineForOffset(pc, PC_LINE_LOOKAHEAD);
|
||||
if (srcline1) {
|
||||
// try to find the next line and bound the PC
|
||||
let srcline2 = file.lines[srcline1.line+1];
|
||||
if (!srcline2 || pc < srcline2.offset) {
|
||||
let score = pc - srcline1.offset;
|
||||
if (score < bestscore) {
|
||||
bestid = wndid;
|
||||
bestscore = pc-res.offset;
|
||||
bestscore = score;
|
||||
}
|
||||
}
|
||||
//console.log(hex(pc,4), srcline1, srcline2, wndid, lstfn, bestid, bestscore);
|
||||
}
|
||||
//console.log(hex(pc,4), wndid, lstfn, bestid, bestscore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1464,15 +1480,18 @@ function uiDebugCallback(state: EmuState) {
|
|||
debugTickPaused = true;
|
||||
}
|
||||
|
||||
function setupDebugCallback(btnid? : string) {
|
||||
if (platform.setupDebug) platform.setupDebug((state:EmuState, msg:string) => {
|
||||
function setupDebugCallback(btnid? : DebugCommandType) {
|
||||
if (platform.setupDebug) {
|
||||
platform.setupDebug((state:EmuState, msg:string) => {
|
||||
uiDebugCallback(state);
|
||||
setDebugButtonState(btnid||"pause", "stopped");
|
||||
msg && showErrorAlert([{msg:"STOPPED: " + msg, line:0}], true);
|
||||
});
|
||||
lastDebugCommand = btnid;
|
||||
}
|
||||
}
|
||||
|
||||
function setupBreakpoint(btnid? : string) {
|
||||
function setupBreakpoint(btnid? : DebugCommandType) {
|
||||
if (!checkRunReady()) return;
|
||||
_disableRecording();
|
||||
setupDebugCallback(btnid);
|
||||
|
|
|
@ -304,12 +304,15 @@ export class MemoryMapView implements ProjectView {
|
|||
|
||||
// TODO: clear buffer when scrubbing
|
||||
|
||||
const OPAQUE_BLACK = 0xff000000;
|
||||
|
||||
export abstract class ProbeViewBaseBase {
|
||||
probe : ProbeRecorder;
|
||||
tooldiv : HTMLElement;
|
||||
cumulativeData : boolean = false;
|
||||
cyclesPerLine : number;
|
||||
totalScanlines : number;
|
||||
sp : number; // stack pointer
|
||||
|
||||
abstract tick() : void;
|
||||
|
||||
|
@ -369,15 +372,19 @@ export abstract class ProbeViewBaseBase {
|
|||
var row=0;
|
||||
var col=0;
|
||||
var clk=0;
|
||||
this.sp = 0;
|
||||
for (var i=0; i<p.idx; i++) {
|
||||
var word = p.buf[i];
|
||||
var addr = word & 0xffff;
|
||||
var value = (word >> 16) & 0xff;
|
||||
var op = word & 0xff000000;
|
||||
var op = word & OPAQUE_BLACK;
|
||||
switch (op) {
|
||||
case ProbeFlags.SCANLINE: row++; col=0; break;
|
||||
case ProbeFlags.FRAME: row=0; col=0; break;
|
||||
case ProbeFlags.CLOCKS: col += addr; clk += addr; break;
|
||||
case ProbeFlags.SP_PUSH:
|
||||
case ProbeFlags.SP_POP:
|
||||
this.sp = addr;
|
||||
default:
|
||||
eventfn(op, addr, col, row, clk, value);
|
||||
break;
|
||||
|
@ -406,7 +413,7 @@ export abstract class ProbeViewBaseBase {
|
|||
return s;
|
||||
}
|
||||
|
||||
getOpRGB(op:number) : number {
|
||||
getOpRGB(op:number, addr:number) : number {
|
||||
switch (op) {
|
||||
case ProbeFlags.EXECUTE: return 0x018001;
|
||||
case ProbeFlags.MEM_READ: return 0x800101;
|
||||
|
@ -415,7 +422,7 @@ export abstract class ProbeViewBaseBase {
|
|||
case ProbeFlags.IO_WRITE: return 0xc00180;
|
||||
case ProbeFlags.VRAM_READ: return 0x808001;
|
||||
case ProbeFlags.VRAM_WRITE: return 0x4080c0;
|
||||
case ProbeFlags.INTERRUPT: return 0xcfcfcf;
|
||||
case ProbeFlags.INTERRUPT: return 0x3fbf3f;
|
||||
case ProbeFlags.ILLEGAL: return 0x3f3fff;
|
||||
default: return 0;
|
||||
}
|
||||
|
@ -519,14 +526,17 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
|
|||
|
||||
refresh() {
|
||||
this.tick();
|
||||
this.datau32.fill(0xff000000);
|
||||
this.datau32.fill(OPAQUE_BLACK);
|
||||
}
|
||||
tick() {
|
||||
super.tick();
|
||||
this.drawImage();
|
||||
}
|
||||
drawImage() {
|
||||
this.ctx.putImageData(this.imageData, 0, 0);
|
||||
}
|
||||
clear() {
|
||||
this.datau32.fill(0xff000000);
|
||||
this.datau32.fill(OPAQUE_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,17 +551,17 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
|
|||
var v = platform.readAddress(i);
|
||||
var rgb = (v >> 2) | (v & 0x1f);
|
||||
rgb |= (rgb<<8) | (rgb<<16);
|
||||
this.datau32[i] = rgb | 0xff000000;
|
||||
this.datau32[i] = rgb | OPAQUE_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
drawEvent(op, addr, col, row) {
|
||||
var rgb = this.getOpRGB(op);
|
||||
var rgb = this.getOpRGB(op, addr);
|
||||
if (!rgb) return;
|
||||
var x = addr & 0xff;
|
||||
var y = (addr >> 8) & 0xff;
|
||||
var data = this.datau32[addr & 0xffff];
|
||||
data = data | rgb | 0xff000000;
|
||||
data = data | rgb | OPAQUE_BLACK;
|
||||
this.datau32[addr & 0xffff] = data;
|
||||
}
|
||||
|
||||
|
@ -589,12 +599,62 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
|
|||
export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectView {
|
||||
|
||||
drawEvent(op, addr, col, row) {
|
||||
var iofs = col + row * this.canvas.width;
|
||||
var rgb = this.getOpRGB(op);
|
||||
var rgb = this.getOpRGB(op, addr);
|
||||
if (!rgb) return;
|
||||
var data = this.datau32[iofs];
|
||||
data = data | rgb | 0xff000000;
|
||||
this.datau32[iofs] = data;
|
||||
var iofs = col + row * this.canvas.width;
|
||||
var data = rgb | OPAQUE_BLACK;
|
||||
this.datau32[iofs] |= data;
|
||||
}
|
||||
|
||||
drawImage() {
|
||||
// fill in the gaps
|
||||
let last = OPAQUE_BLACK;
|
||||
for (let i=0; i<this.datau32.length; i++) {
|
||||
if (this.datau32[i] == OPAQUE_BLACK) {
|
||||
this.datau32[i] = last;
|
||||
} else {
|
||||
last = this.datau32[i];
|
||||
}
|
||||
}
|
||||
super.drawImage();
|
||||
}
|
||||
}
|
||||
|
||||
export class RasterStackMapView extends RasterPCHeatMapView implements ProjectView {
|
||||
|
||||
interrupt: number = 0;
|
||||
rgb: number = 0;
|
||||
lastpc: number = 0;
|
||||
|
||||
drawEvent(op, addr, col, row) {
|
||||
var iofs = col + row * this.canvas.width;
|
||||
// track interrupts
|
||||
if (op == ProbeFlags.INTERRUPT) this.interrupt = 1;
|
||||
if (this.interrupt == 1 && op == ProbeFlags.SP_PUSH) this.interrupt = addr;
|
||||
if (this.interrupt > 1 && this.sp > this.interrupt) this.interrupt = 0;
|
||||
// track writes
|
||||
if (op == ProbeFlags.MEM_WRITE) { this.rgb |= 0x00002f; }
|
||||
if (op == ProbeFlags.VRAM_WRITE) { this.rgb |= 0x003f80; }
|
||||
if (op == ProbeFlags.IO_WRITE) { this.rgb |= 0x1f3f80; }
|
||||
if (op == ProbeFlags.IO_READ) { this.rgb |= 0x001f00; }
|
||||
// draw pixels?
|
||||
if (op == ProbeFlags.ILLEGAL) {
|
||||
this.datau32[iofs] = 0xff0f0f0f;
|
||||
} else {
|
||||
let data = this.rgb;
|
||||
if (op == ProbeFlags.EXECUTE) {
|
||||
let sp = this.sp & 15;
|
||||
if (sp >= 8) sp = 16-sp;
|
||||
if (Math.abs(this.lastpc) - addr > 16) { sp += 1; }
|
||||
if (Math.abs(this.lastpc) - addr > 256) { sp += 1; }
|
||||
data = this.rgb = (0x080808 * sp) + 0x202020;
|
||||
this.lastpc = addr;
|
||||
}
|
||||
if (this.interrupt) { data |= 0x800040; }
|
||||
if (this.datau32[iofs] == OPAQUE_BLACK) {
|
||||
this.datau32[iofs] = data | OPAQUE_BLACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,7 +732,7 @@ export class ScanlineIOView extends ProbeViewBaseBase {
|
|||
var opaddr = line[i];
|
||||
if (opaddr !== undefined) {
|
||||
var addr = opaddr & 0xffff;
|
||||
var op = op & 0xff000000;
|
||||
var op = op & OPAQUE_BLACK;
|
||||
if (op == ProbeFlags.EXECUTE) {
|
||||
s += ',';
|
||||
} else {
|
||||
|
|
|
@ -23,6 +23,9 @@ function createTextSpan(text:string, className:string) : HTMLElement {
|
|||
|
||||
/////
|
||||
|
||||
// look ahead this many bytes when finding source lines for a PC
|
||||
export const PC_LINE_LOOKAHEAD = 64;
|
||||
|
||||
const MAX_ERRORS = 200;
|
||||
|
||||
const MODEDEFS = {
|
||||
|
@ -384,7 +387,7 @@ export class SourceEditor implements ProjectView {
|
|||
cpustate = platform.getCPUState();
|
||||
if (cpustate) {
|
||||
var EPC = (cpustate && (cpustate.EPC || cpustate.PC));
|
||||
var res = this.sourcefile.findLineForOffset(EPC, 15);
|
||||
var res = this.sourcefile.findLineForOffset(EPC, PC_LINE_LOOKAHEAD);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -598,7 +601,7 @@ export class ListingView extends DisassemblerView implements ProjectView {
|
|||
var state = lastDebugState || platform.saveState();
|
||||
var pc = state.c ? (state.c.EPC || state.c.PC) : 0;
|
||||
if (pc >= 0 && this.assemblyfile) {
|
||||
var res = this.assemblyfile.findLineForOffset(pc, 15);
|
||||
var res = this.assemblyfile.findLineForOffset(pc, PC_LINE_LOOKAHEAD);
|
||||
if (res) {
|
||||
// set cursor while debugging
|
||||
if (moveCursor) {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
import { MOS6502, MOS6502State } from "../common/cpu/MOS6502";
|
||||
import { BasicMachine, RasterFrameBased, Bus, ProbeAll, Probeable, NullProbe } from "../common/devices";
|
||||
import { KeyFlags, newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler, EmuHalt, dumpRAM } from "../common/emu";
|
||||
import { lzgmini, stringToByteArray, hex, rgb2bgr } from "../common/util";
|
||||
import { AcceptsPaddleInput, Probeable } from "../common/devices";
|
||||
import { dumpRAM, KeyFlags } from "../common/emu";
|
||||
import { clamp, hex, lpad } from "../common/util";
|
||||
|
||||
// https://www.c64-wiki.com/wiki/C64
|
||||
// http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt
|
||||
|
@ -16,7 +15,8 @@ import { Machine } from "../common/baseplatform";
|
|||
import { TrapCondition } from "../common/devices";
|
||||
import { BaseWASMMachine } from "../common/wasmplatform";
|
||||
|
||||
export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeable {
|
||||
export class C64_WASMMachine extends BaseWASMMachine
|
||||
implements Machine, Probeable, AcceptsPaddleInput {
|
||||
|
||||
numTotalScanlines = 312;
|
||||
cpuCyclesPerLine = 63;
|
||||
|
@ -24,6 +24,8 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
prgstart : number;
|
||||
joymask0 = 0;
|
||||
joymask1 = 0;
|
||||
lightpen_x = 0;
|
||||
lightpen_y = 0;
|
||||
|
||||
loadBIOS(srcArray: Uint8Array) {
|
||||
var patch1ofs = 0xea24 - 0xe000 + 0x3000;
|
||||
|
@ -34,7 +36,7 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
super.reset();
|
||||
// clear keyboard
|
||||
for (var ch=0; ch<128; ch++) {
|
||||
this.setKeyInput(ch, 0, KeyFlags.KeyUp);
|
||||
this.exports.machine_key_up(this.sys, ch);
|
||||
}
|
||||
// load rom
|
||||
if (this.romptr && this.romlen) {
|
||||
|
@ -50,12 +52,12 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
// advance BIOS a few frames
|
||||
this.exports.machine_exec(this.sys, 250000);
|
||||
// type in command (SYS 2061)
|
||||
var cmd = "SYS "+this.prgstart+"\r";
|
||||
var cmd = "\rSYS "+this.prgstart+"\r";
|
||||
for (var i=0; i<cmd.length; i++) {
|
||||
var key = cmd.charCodeAt(i);
|
||||
this.exports.machine_exec(this.sys, 20000);
|
||||
this.exports.machine_key_down(this.sys, key);
|
||||
this.exports.machine_exec(this.sys, 20000);
|
||||
this.exports.machine_exec(this.sys, 5000);
|
||||
this.exports.machine_key_up(this.sys, key);
|
||||
}
|
||||
// advance clock until program starts
|
||||
|
@ -78,12 +80,14 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
}
|
||||
advanceFrame(trap: TrapCondition) : number {
|
||||
// TODO: does this sync with VSYNC?
|
||||
var scanline = this.exports.machine_get_raster_line(this.sys);
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * (19656+295) / this.numTotalScanlines);
|
||||
// TODO: ticks, not msec (machine_tick() has different rate then machine_exec())
|
||||
var scanline = this.getRasterY();
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * 19656 / this.numTotalScanlines);
|
||||
var probing = this.probe != null;
|
||||
if (probing) this.exports.machine_reset_probe_buffer();
|
||||
clocks = super.advanceFrameClock(trap, clocks);
|
||||
if (probing) this.copyProbeData();
|
||||
//console.log(clocks, this.getRasterY());
|
||||
return clocks;
|
||||
}
|
||||
getCPUState() {
|
||||
|
@ -103,18 +107,26 @@ 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() {
|
||||
this.exports.machine_save_state(this.sys, this.stateptr);
|
||||
/*
|
||||
for (var i=0; i<this.statearr.length; i++)
|
||||
if (this.statearr[i] == 0xa0 && this.statearr[i+1] == 0x4d && this.statearr[i+2] == 0xe2) console.log(hex(i));
|
||||
*/
|
||||
let cia1 = this.getDebugStateOffset(1);
|
||||
let cia2 = this.getDebugStateOffset(2);
|
||||
let vic = this.getDebugStateOffset(3);
|
||||
let sid = this.getDebugStateOffset(4);
|
||||
let ramofs = this.getDebugStateOffset(5);
|
||||
let pla = this.getDebugStateOffset(9);
|
||||
return {
|
||||
c:this.getCPUState(),
|
||||
state:this.statearr.slice(0),
|
||||
ram:this.statearr.slice(18640, 18640+0x200), // ZP and stack
|
||||
ram:this.statearr.slice(ramofs, ramofs+0x10000),
|
||||
cia1:this.statearr.slice(cia1, cia1+64),
|
||||
cia2:this.statearr.slice(cia2, cia2+64),
|
||||
vic:this.statearr.slice(vic+1, vic+1+64),
|
||||
sid:this.statearr.slice(sid, sid+32),
|
||||
pla:this.statearr.slice(pla, pla+16)
|
||||
};
|
||||
}
|
||||
loadState(state) : void {
|
||||
|
@ -122,7 +134,7 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
this.exports.machine_load_state(this.sys, this.stateptr);
|
||||
}
|
||||
getVideoParams() {
|
||||
return {width:392, height:272, overscan:true, videoFrequency:50};
|
||||
return {width:392, height:272, overscan:true, videoFrequency:50, aspect:392/272*0.9365};
|
||||
}
|
||||
setKeyInput(key: number, code: number, flags: number): void {
|
||||
// TODO: handle shifted keys
|
||||
|
@ -132,22 +144,36 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
// convert to c64
|
||||
var mask = 0;
|
||||
var mask2 = 0;
|
||||
if (key == 37) { key = 0x8; mask = 0x4; } // LEFT
|
||||
if (key == 38) { key = 0xb; mask = 0x1; } // UP
|
||||
if (key == 39) { key = 0x9; mask = 0x8; } // RIGHT
|
||||
if (key == 40) { key = 0xa; mask = 0x2; } // DOWN
|
||||
if (key == 32) { mask = 0x10; } // FIRE
|
||||
/* player 2 (TODO)
|
||||
if (key == 65) { key = 65; mask2 = 0x4; } // LEFT
|
||||
if (key == 87) { key = 87; mask2 = 0x1; } // UP
|
||||
if (key == 68) { key = 68; mask2 = 0x8; } // RIGHT
|
||||
if (key == 83) { key = 83; mask2 = 0x2; } // DOWN
|
||||
if (key == 69) { mask2 = 0x10; } // FIRE
|
||||
*/
|
||||
if (key == 113) { key = 0xf1; } // F2
|
||||
if (key == 115) { key = 0xf3; } // F4
|
||||
if (key == 119) { key = 0xf5; } // F8
|
||||
if (key == 121) { key = 0xf7; } // F10
|
||||
switch (key) {
|
||||
case 32: mask = 0x10; break;
|
||||
case 37: key = 0x8; mask = 0x4; break; // LEFT
|
||||
case 38: key = 0xb; mask = 0x1; break; // UP
|
||||
case 39: key = 0x9; mask = 0x8; break; // RIGHT
|
||||
case 40: key = 0xa; mask = 0x2; break; // DOWN
|
||||
case 113: key = 0xf1; break; // F2
|
||||
case 115: key = 0xf3; break; // F4
|
||||
case 119: key = 0xf5; break; // F8
|
||||
case 121: key = 0xf7; break; // F10
|
||||
case 188: key = flags & KeyFlags.Shift ? 0x3c : 0x2e; break; // < .
|
||||
case 190: key = flags & KeyFlags.Shift ? 0x3e : 0x2c; break; // > ,
|
||||
case 191: key = flags & KeyFlags.Shift ? 0x3f : 0x2f; break; // ? /
|
||||
case 222: key = flags & KeyFlags.Shift ? 0x22 : 0x27; break; // " '
|
||||
case 219: key = flags & KeyFlags.Shift ? 0x7b : 0x5b; break; // [
|
||||
case 221: key = flags & KeyFlags.Shift ? 0x7d : 0x5d; break; // ]
|
||||
case 48: if (flags & KeyFlags.Shift) key = 0x29; break; // )
|
||||
case 49: if (flags & KeyFlags.Shift) key = 0x21; break; // !
|
||||
case 50: if (flags & KeyFlags.Shift) key = 0x40; break; // @
|
||||
case 51: if (flags & KeyFlags.Shift) key = 0x23; break; // #
|
||||
case 52: if (flags & KeyFlags.Shift) key = 0x24; break; // $
|
||||
case 53: if (flags & KeyFlags.Shift) key = 0x25; break; // %
|
||||
case 54: if (flags & KeyFlags.Shift) key = 0x5e; break; // ^
|
||||
case 55: if (flags & KeyFlags.Shift) key = 0x26; break; // &
|
||||
case 56: if (flags & KeyFlags.Shift) key = 0x2a; break; // *
|
||||
case 57: if (flags & KeyFlags.Shift) key = 0x28; break; // (
|
||||
case 59: if (flags & KeyFlags.Shift) key = 0x3a; break; // ;
|
||||
case 61: if (flags & KeyFlags.Shift) key = 0x2b; break; // +
|
||||
case 173: key = flags & KeyFlags.Shift ? 0x5f : 0x2d; break; // _ -
|
||||
}
|
||||
if (flags & KeyFlags.KeyDown) {
|
||||
this.exports.machine_key_down(this.sys, key);
|
||||
this.joymask0 |= mask;
|
||||
|
@ -159,5 +185,87 @@ export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeab
|
|||
}
|
||||
this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1);
|
||||
}
|
||||
getRasterY() {
|
||||
return this.exports.machine_get_raster_line(this.sys);
|
||||
}
|
||||
getDebugStateOffset(index: number) {
|
||||
var p = this.exports.machine_get_debug_pointer(this.sys, index);
|
||||
return p - this.sys;
|
||||
}
|
||||
getDebugCategories() {
|
||||
return ['CPU','ZPRAM','Stack','PLA','CIA','VIC','SID'];
|
||||
}
|
||||
getDebugInfo(category:string, state:any) {
|
||||
switch (category) {
|
||||
case 'PLA': {
|
||||
let s = "";
|
||||
let iomapped = state.pla[0];
|
||||
let port = state.pla[3];
|
||||
s += `$0000 - $9FFF RAM\n`;
|
||||
s += `$A000 - $BFFF ${(port&3)==3 ? 'BASIC ROM' : 'RAM'}\n`;
|
||||
s += `$C000 - $CFFF RAM\n`;
|
||||
s += `$D000 - $DFFF ${iomapped ? 'I/O' : (port&3)!=0 ? 'CHAR ROM' : 'RAM'}\n`;
|
||||
s += `$E000 - $FFFF ${(port&2)==2 ? 'KERNAL ROM' : 'RAM'}\n`;
|
||||
return s;
|
||||
}
|
||||
case 'CIA': {
|
||||
let s = "";
|
||||
for (let i=0; i<2; i++) {
|
||||
let m = i ? state.cia2 : state.cia1;
|
||||
s += `CIA ${i+1}\n`;
|
||||
s += ` A: Data ${hex(m[0])} DDR ${hex(m[1])} Input ${hex(m[2])}`;
|
||||
s += ` Timer ${hex(m[10]+m[11]*256, 4)}\n`;
|
||||
s += ` B: Data ${hex(m[4])} DDR ${hex(m[5])} Input ${hex(m[6])}`;
|
||||
s += ` Timer ${hex(m[10+10]+m[11+10]*256, 4)}\n`;
|
||||
//s += ` IMR ${hex(m[48])} ICR ${hex(m[50])}\n`
|
||||
}
|
||||
return s;
|
||||
}
|
||||
case 'VIC': {
|
||||
let m = state.vic;
|
||||
let s = '';
|
||||
let vicbank = ((state.cia2[0] & 3) ^ 3) * 0x4000;
|
||||
let charmem = vicbank + (state.vic[0x18] & 14) * 0x400;
|
||||
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;
|
||||
let rasterX = state.state[0xf4];
|
||||
let rasterY = this.getRasterY();
|
||||
s += 'Mode:';
|
||||
if (state.vic[0x11] & 0x20) s += ' BITMAP'; else s += ' CHAR';
|
||||
if (state.vic[0x16] & 0x10) s += ' MULTICOLOR';
|
||||
if (state.vic[0x11] & 0x40) s += ' EXTENDED';
|
||||
s += "\n";
|
||||
s += `Raster: (${lpad(rasterX,3)}, ${lpad(rasterY,3)}) `;
|
||||
s += `Scroll: (${state.vic[0x16] & 7}, ${state.vic[0x11] & 7})`;
|
||||
s += "\n";
|
||||
s += `VIC Bank: $${hex(vicbank,4)} Scrn: $${hex(screen,4)} `;
|
||||
if (isbitmap) s += `Bitmap: $${hex(charmem&0xe000,4)}`
|
||||
else if (ischar) s += `Char: ROM $${hex(charmem,4)}`;
|
||||
else s += `Char: $${hex(charmem,4)}`;
|
||||
s += "\n";
|
||||
s += dumpRAM(m, 0xd000, 64);
|
||||
return s;
|
||||
}
|
||||
case 'SID': {
|
||||
let m = state.sid;
|
||||
let s = ''
|
||||
s += dumpRAM(m, 0xd400, 32);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPaddleInput(controller: number, value: number): void {
|
||||
if (controller == 0) this.lightpen_x = value;
|
||||
if (controller == 1) this.lightpen_y = value;
|
||||
const x1 = 22;
|
||||
const y1 = 36;
|
||||
const x2 = 228;
|
||||
const y2 = 220;
|
||||
let x = clamp(0, 255, (this.lightpen_x - x1) / (x2 - x1) * 160 + 24);
|
||||
let y = clamp(0, 255, (this.lightpen_y - y1) / (y2 - y1) * 200 + 50);
|
||||
this.exports.machine_set_mouse(this.sys, x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,14 +58,17 @@ export class CPC_WASMMachine extends BaseWASMMachine implements Machine {
|
|||
}
|
||||
}
|
||||
advanceFrame(trap: TrapCondition) : number {
|
||||
var scanline = this.exports.machine_get_raster_line(this.sys);
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * 19965 / this.numTotalScanlines);
|
||||
var scanline = this.getRasterY();
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * (4000000/50) / this.numTotalScanlines);
|
||||
var probing = this.probe != null;
|
||||
if (probing) this.exports.machine_reset_probe_buffer();
|
||||
clocks = super.advanceFrameClock(trap, clocks);
|
||||
if (probing) this.copyProbeData();
|
||||
return clocks;
|
||||
}
|
||||
getRasterY() {
|
||||
return this.exports.machine_get_raster_line(this.sys);
|
||||
}
|
||||
/*
|
||||
z80_tick_t tick_cb; // 0
|
||||
uint64_t bc_de_hl_fa; // 8
|
||||
|
|
|
@ -73,14 +73,17 @@ export class VIC20_WASMMachine extends BaseWASMMachine implements Machine, Probe
|
|||
}
|
||||
advanceFrame(trap: TrapCondition) : number {
|
||||
// TODO: does this sync with VSYNC?
|
||||
var scanline = this.exports.machine_get_raster_line(this.sys);
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * (19656+295+32) / this.numTotalScanlines);
|
||||
var scanline = this.getRasterY();
|
||||
var clocks = Math.floor((this.numTotalScanlines - scanline) * 19656 / this.numTotalScanlines);
|
||||
var probing = this.probe != null;
|
||||
if (probing) this.exports.machine_reset_probe_buffer();
|
||||
clocks = super.advanceFrameClock(trap, clocks);
|
||||
if (probing) this.copyProbeData();
|
||||
return clocks;
|
||||
}
|
||||
getRasterY() {
|
||||
return this.exports.machine_get_raster_line(this.sys);
|
||||
}
|
||||
getCPUState() {
|
||||
this.exports.machine_save_cpu_state(this.sys, this.cpustateptr);
|
||||
var s = this.cpustatearr;
|
||||
|
|
|
@ -20,7 +20,7 @@ export class ZX_WASMMachine extends BaseWASMMachine implements Machine {
|
|||
reset() {
|
||||
super.reset();
|
||||
// advance bios
|
||||
this.exports.machine_exec(this.sys, 500000); // TODO?
|
||||
this.exports.machine_exec(this.sys, 2000000);
|
||||
// load rom (Z80 header: https://worldofspectrum.org/faq/reference/z80format.htm)
|
||||
if (this.romptr && this.romlen) {
|
||||
// TODO
|
||||
|
@ -41,7 +41,7 @@ export class ZX_WASMMachine extends BaseWASMMachine implements Machine {
|
|||
//var scanline = this.exports.machine_get_raster_line(this.sys);
|
||||
var probing = this.probe != null;
|
||||
if (probing) this.exports.machine_reset_probe_buffer();
|
||||
var clocks = super.advanceFrameClock(trap, Math.floor(1000000 / 50)); // TODO: use ticks, not msec
|
||||
var clocks = super.advanceFrameClock(trap, Math.floor(3500000 / 50));
|
||||
if (probing) this.copyProbeData();
|
||||
return clocks;
|
||||
}
|
||||
|
|
|
@ -6,28 +6,39 @@ 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:'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:'climber.c', name:'Climber Game (C)'},
|
||||
{id:'multilines.c', name:'Multicolor Lines+Flood Fill (C)'},
|
||||
{id:'sidtune.dasm', name:'SID Tune (ASM)'},
|
||||
{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:'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:'test_multiplex.c', name:'Sprite Retriggering'},
|
||||
{id:'test_multispritelib.c', name:'Sprite Multiplexing Library'},
|
||||
{id:'scrolling_text.c', name:'Big Scrolling Text'},
|
||||
{id:'mcbitmap.c', name:'Multicolor Bitmap Mode'},
|
||||
//{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 Player Demo'},
|
||||
{id:'climber.c', name:'Climber Game'},
|
||||
];
|
||||
|
||||
const C64_MEMORY_MAP = { main:[
|
||||
{name:'6510 Registers',start:0x0, size:0x2,type:'io'},
|
||||
{name:'BIOS Reserved', start:0x200, size:0xa7},
|
||||
{name:'Default Screen RAM', start:0x400, size:1024,type:'ram'},
|
||||
//{name:'RAM', start:0x2, size:0x7ffe,type:'ram'},
|
||||
{name:'Cartridge ROM',start:0x8000,size:0x2000,type:'rom'},
|
||||
{name:'BASIC ROM', start:0xa000,size:0x2000,type:'rom'},
|
||||
{name:'RAM', start:0xc000,size:0x1000,type:'ram'},
|
||||
{name:'Upper RAM', start:0xc000,size:0x1000,type:'ram'},
|
||||
{name:'Character ROM',start:0xd000,size:0x1000,type:'rom'},
|
||||
{name:'VIC-II I/O', start:0xd000,size:0x0400,type:'io'},
|
||||
{name:'SID', start:0xd400,size:0x0400,type:'io'},
|
||||
{name:'Color RAM', start:0xd800,size:0x0400,type:'io'},
|
||||
|
|
|
@ -138,6 +138,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
|
|||
// insert debug hook
|
||||
this.nes.cpu._emulate = this.nes.cpu.emulate;
|
||||
this.nes.cpu.emulate = () => {
|
||||
if (this.nes.cpu.irqRequested) this.probe.logInterrupt(this.nes.cpu.irqType || 0);
|
||||
this.probe.logExecute(this.nes.cpu.REG_PC+1, this.nes.cpu.REG_SP);
|
||||
var cycles = this.nes.cpu._emulate();
|
||||
this.evalDebugCondition();
|
||||
|
|
|
@ -394,7 +394,8 @@ class VCSPlatform extends BasePlatform {
|
|||
bus.oldWrite = bus.write;
|
||||
bus.write = function(a,v) {
|
||||
this.oldWrite(a,v);
|
||||
if (a < 0x80) probe.logIOWrite(a,v);
|
||||
if (a == 0x02) probe.logIllegal(a); // WSYNC
|
||||
else if (a < 0x80) probe.logIOWrite(a,v);
|
||||
else if (a > 0x280 && a < 0x300) probe.logIOWrite(a,v);
|
||||
else probe.logWrite(a,v);
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":[{"filename":"/common/snes/icd2.wiz","start":0,"end":2959},{"filename":"/common/snes/img2snes.py","start":2959,"end":5920},{"filename":"/common/snes/minirpg_sprites.png","start":5920,"end":7519},{"filename":"/common/snes/hello_tiles_compact.png","start":7519,"end":8122},{"filename":"/common/snes/hello_tiles_compact.chr","start":8122,"end":9658},{"filename":"/common/snes/hello_tiles.png","start":9658,"end":10295},{"filename":"/common/snes/hello_tiles.chr","start":10295,"end":18487},{"filename":"/common/snes/snes.wiz","start":18487,"end":42074},{"filename":"/common/snes/minirpg_sprites.chr","start":42074,"end":50266},{"filename":"/common/gg/sms.wiz","start":50266,"end":56495},{"filename":"/common/gg/minirpg_sprites.png","start":56495,"end":58094},{"filename":"/common/gg/hello_tiles.png","start":58094,"end":58731},{"filename":"/common/gg/img2gg8.py","start":58731,"end":61609},{"filename":"/common/gg/hello_tiles.chr","start":61609,"end":69801},{"filename":"/common/gg/img2gg16.py","start":69801,"end":73816},{"filename":"/common/gg/minirpg_sprites.chr","start":73816,"end":82008},{"filename":"/common/nes/scroller_tiles.chr","start":82008,"end":86104},{"filename":"/common/nes/minirpg_sprites.png","start":86104,"end":87701},{"filename":"/common/nes/hello_tiles.png","start":87701,"end":88138},{"filename":"/common/nes/img2chr.py","start":88138,"end":90528},{"filename":"/common/nes/hello_tiles.chr","start":90528,"end":94624},{"filename":"/common/nes/scroller_tiles.png","start":94624,"end":95467},{"filename":"/common/nes/bobble_tiles.png","start":95467,"end":96149},{"filename":"/common/nes/nes.wiz","start":96149,"end":115238},{"filename":"/common/nes/bobble_tiles.chr","start":115238,"end":119334},{"filename":"/common/nes/minirpg_sprites.chr","start":119334,"end":123430},{"filename":"/common/msx/img2msx16.py","start":123430,"end":125505},{"filename":"/common/msx/hello_tiles.png","start":125505,"end":125998},{"filename":"/common/msx/hello_tiles.chr","start":125998,"end":128046},{"filename":"/common/msx/img2msx8.py","start":128046,"end":130360},{"filename":"/common/msx/msx.wiz","start":130360,"end":185578},{"filename":"/common/pce/pce.wiz","start":185578,"end":198258},{"filename":"/common/pce/minirpg_sprites.png","start":198258,"end":199857},{"filename":"/common/pce/hello_tiles.png","start":199857,"end":200494},{"filename":"/common/pce/hello_tiles.chr","start":200494,"end":208686},{"filename":"/common/pce/img2pce8.py","start":208686,"end":211606},{"filename":"/common/pce/minirpg_sprites.chr","start":211606,"end":219798},{"filename":"/common/gb/bcd.wiz","start":219798,"end":222637},{"filename":"/common/gb/joy.wiz","start":222637,"end":225456},{"filename":"/common/gb/gb.wiz","start":225456,"end":242454},{"filename":"/common/gb/oam.wiz","start":242454,"end":243780},{"filename":"/common/gb/math.wiz","start":243780,"end":246131},{"filename":"/common/gb/sgb_util.wiz","start":246131,"end":249318},{"filename":"/common/gb/memory.wiz","start":249318,"end":250760},{"filename":"/common/gb/gbc_util.wiz","start":250760,"end":251810},{"filename":"/common/2600/vcs.wiz","start":251810,"end":257710},{"filename":"/common/spc/spc.wiz","start":257710,"end":264462}],"remote_package_size":264462,"package_uuid":"f357339c-3604-4f7c-b827-41c09e93a3b5"}
|
||||
{"files":[{"filename":"/common/snes/icd2.wiz","start":0,"end":2959},{"filename":"/common/snes/img2snes.py","start":2959,"end":5920},{"filename":"/common/snes/minirpg_sprites.png","start":5920,"end":7519},{"filename":"/common/snes/hello_tiles_compact.png","start":7519,"end":8122},{"filename":"/common/snes/hello_tiles_compact.chr","start":8122,"end":9658},{"filename":"/common/snes/hello_tiles.png","start":9658,"end":10295},{"filename":"/common/snes/hello_tiles.chr","start":10295,"end":18487},{"filename":"/common/snes/snes.wiz","start":18487,"end":42074},{"filename":"/common/snes/minirpg_sprites.chr","start":42074,"end":50266},{"filename":"/common/gg/sms.wiz","start":50266,"end":56495},{"filename":"/common/gg/minirpg_sprites.png","start":56495,"end":58094},{"filename":"/common/gg/hello_tiles.png","start":58094,"end":58731},{"filename":"/common/gg/img2gg8.py","start":58731,"end":61609},{"filename":"/common/gg/hello_tiles.chr","start":61609,"end":69801},{"filename":"/common/gg/img2gg16.py","start":69801,"end":73816},{"filename":"/common/gg/minirpg_sprites.chr","start":73816,"end":82008},{"filename":"/common/nes/scroller_tiles.chr","start":82008,"end":86104},{"filename":"/common/nes/minirpg_sprites.png","start":86104,"end":87701},{"filename":"/common/nes/hello_tiles.png","start":87701,"end":88138},{"filename":"/common/nes/img2chr.py","start":88138,"end":90528},{"filename":"/common/nes/hello_tiles.chr","start":90528,"end":94624},{"filename":"/common/nes/scroller_tiles.png","start":94624,"end":95467},{"filename":"/common/nes/bobble_tiles.png","start":95467,"end":96149},{"filename":"/common/nes/nes.wiz","start":96149,"end":115238},{"filename":"/common/nes/bobble_tiles.chr","start":115238,"end":119334},{"filename":"/common/nes/minirpg_sprites.chr","start":119334,"end":123430},{"filename":"/common/msx/img2msx16.py","start":123430,"end":125505},{"filename":"/common/msx/hello_tiles.png","start":125505,"end":125998},{"filename":"/common/msx/hello_tiles.chr","start":125998,"end":128046},{"filename":"/common/msx/img2msx8.py","start":128046,"end":130360},{"filename":"/common/msx/msx.wiz","start":130360,"end":185578},{"filename":"/common/pce/pce.wiz","start":185578,"end":198258},{"filename":"/common/pce/minirpg_sprites.png","start":198258,"end":199857},{"filename":"/common/pce/hello_tiles.png","start":199857,"end":200494},{"filename":"/common/pce/hello_tiles.chr","start":200494,"end":208686},{"filename":"/common/pce/img2pce8.py","start":208686,"end":211606},{"filename":"/common/pce/minirpg_sprites.chr","start":211606,"end":219798},{"filename":"/common/gb/bcd.wiz","start":219798,"end":222637},{"filename":"/common/gb/joy.wiz","start":222637,"end":225456},{"filename":"/common/gb/gb.wiz","start":225456,"end":242454},{"filename":"/common/gb/oam.wiz","start":242454,"end":243780},{"filename":"/common/gb/math.wiz","start":243780,"end":246131},{"filename":"/common/gb/sgb_util.wiz","start":246131,"end":249318},{"filename":"/common/gb/memory.wiz","start":249318,"end":250760},{"filename":"/common/gb/gbc_util.wiz","start":250760,"end":251810},{"filename":"/common/2600/vcs.wiz","start":251810,"end":257710},{"filename":"/common/spc/spc.wiz","start":257710,"end":264462}],"remote_package_size":264462,"package_uuid":"3682f967-645c-4761-b3e6-5a07a4ad8a35"}
|
|
@ -119,9 +119,9 @@ export function assembleCA65(step: BuildStep): BuildStepResult {
|
|||
}
|
||||
execMain(step, CA65, args);
|
||||
if (errors.length) {
|
||||
// TODO?
|
||||
let listings : CodeListingMap = {};
|
||||
listings[step.path] = { lines:[], text:getWorkFileAsString(step.path) };
|
||||
// TODO? change extension to .lst
|
||||
//listings[step.path] = { lines:[], text:getWorkFileAsString(step.path) };
|
||||
return { errors, listings };
|
||||
}
|
||||
objout = FS.readFile(objpath, { encoding: 'binary' });
|
||||
|
|
Binary file not shown.
|
@ -1188,6 +1188,7 @@ var TOOL_PRELOADFS = {
|
|||
'wiz': 'wiz',
|
||||
'ecs-vcs': '65-none', // TODO: support multiple platforms
|
||||
'ecs-nes': '65-nes', // TODO: support multiple platforms
|
||||
'ecs-c64': '65-c64', // TODO: support multiple platforms
|
||||
}
|
||||
|
||||
//const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay)); // for testing
|
||||
|
|
|
@ -44,6 +44,7 @@ async function doBuild(msgs, callback, outlen, nlines, nerrors, options) {
|
|||
}
|
||||
assert.ok(err.msg);
|
||||
}
|
||||
if (nerrors != msg.errors.length) console.log(msg);
|
||||
assert.equal(nerrors, msg.errors.length);
|
||||
} else {
|
||||
assert.equal(nerrors||0, 0);
|
||||
|
@ -242,7 +243,8 @@ describe('Worker', function() {
|
|||
});
|
||||
it('should compile C64 cc65 skeleton', function(done) {
|
||||
var csource = ab2str(fs.readFileSync('presets/c64/skeleton.cc65'));
|
||||
compile('cc65', csource, 'c64.wasm', done, 2663, 2, 0);
|
||||
csource = csource.replace('#include "','//');
|
||||
compile('cc65', csource, 'c64.wasm', done, 3001, 3, 0);
|
||||
});
|
||||
it('should compile zmachine inform6 skeleton', function(done) {
|
||||
var csource = ab2str(fs.readFileSync('presets/zmachine/skeleton.inform6'));
|
||||
|
|
Loading…
Reference in New Issue
Block a user