From 60e527287e7244d5d6aa3e61ba9cf1f364580361 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 4 Feb 2020 11:58:46 -0600 Subject: [PATCH] asset editor: added toolbar --- presets/c64/climber.c | 239 ++++++++++++++++++++++++++------------- presets/c64/multilines.c | 144 +++++++++++++++++++++++ presets/c64/scroll5.c | 2 +- presets/c64/scrolling.c | 22 ++-- presets/c64/scrolling.h | 2 +- presets/c64/sprites.c | 10 +- src/ide/pixeleditor.ts | 24 ++-- src/platform/c64.ts | 8 +- src/worker/workermain.ts | 7 +- 9 files changed, 351 insertions(+), 107 deletions(-) create mode 100644 presets/c64/multilines.c diff --git a/presets/c64/climber.c b/presets/c64/climber.c index 12051a32..b0d453eb 100644 --- a/presets/c64/climber.c +++ b/presets/c64/climber.c @@ -53,41 +53,17 @@ typedef enum { SND_START, SND_HIT, SND_COIN, SND_JUMP } SFXIndex; ///// CHARS -const byte CHAR_TABLE[8][8] = { - /*{w:8,h:8,brev:1,count:8}*/ - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, - {0xFF,0xBF,0xBF,0x00,0xFF,0xFB,0xFB,0x00}, - {0x81,0xFF,0x81,0x81,0x81,0xFF,0x81,0x81}, - {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}, -}; - -const byte static_sprite_table[2][16*2] = { - /*{w:16,h:16,brev:1,remap:[4,0,1,2,3,5,6,7,8,9],count:4}*/ - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x3F, - 0x35, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x40, 0xFC, - 0x54, 0xAC, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFC, - },{ - 0x00, 0x19, 0x1F, 0x0A, 0x05, 0x07, 0x0E, 0x1C, - 0x3A, 0x2A, 0x3C, 0x2E, 0x1E, 0x18, 0x0E, 0x07, - 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x38, - 0xFC, 0xF4, 0x7C, 0xB4, 0xB8, 0x68, 0xF0, 0xE0, - } -}; - const byte ITEM_CHARS[3][4] = { { 0xe9,0xe9,0x5f,0x69 }, - { 0x7f,0x7f,0x7f,0x7f }, + { 0x55,0x49,0x4a,0x4b }, { 0x7f,0x7f,0x7f,0x7f }, }; -/*{w:12,h:21,bpp:2,brev:1,count:5,aspect:2}*/ -const char SPRITE_DATA[5][3*21] = { +#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] = { + // left direction { 0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xEA,0x00, 0x02,0xEA,0x00,0x02,0xEA,0x00,0x02,0xEA,0x00, @@ -116,13 +92,13 @@ const char SPRITE_DATA[5][3*21] = { 0x0A,0x02,0x94,0x15,0x00,0x94,0x15,0x00,0x04 }, { - 0x00,0x00,0x00,0x00,0xA8,0x00,0x02,0xFE,0x00, - 0x02,0xBA,0x00,0x02,0xBA,0x00,0x02,0xBA,0x00, - 0x00,0xA8,0x00,0x00,0x54,0x08,0x82,0xAA,0xA8, - 0xAA,0xFE,0xA0,0x2A,0xAA,0x80,0x0A,0xFE,0x00, - 0x02,0xAA,0x00,0x03,0xFF,0x00,0x02,0xAA,0x00, - 0x02,0xAA,0x00,0x0A,0x8A,0x80,0x0A,0x02,0x80, - 0x0A,0x02,0x80,0x05,0x01,0x40,0x15,0x01,0x50 + 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, @@ -133,11 +109,82 @@ const char SPRITE_DATA[5][3*21] = { 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 + }, }; -#define NUM_SPRITE_PATTERNS 5 -#define NUM_SPRITE_STATES 4 - ///// GLOBALS // random byte between (a ... b-1) @@ -230,7 +277,7 @@ void scroll_draw_row(byte row) { byte row_height; // rows above bottom of level // set screen/color buffer addresses buf = hidbuf + row*COLS; - attrs = tempbuf + row*COLS; + attrs = colorbuf + row*COLS; row_height = -(row + origin_y); // loop over all floors for (floor=0; floor= 2)) { create_actors_on_floor(floor); } @@ -313,6 +359,40 @@ void draw_entire_stage() { swap_needed = true; } +// y = (256 - origin_y) - floor +void refresh_floor(byte floor) { + byte row = floors[floor].ypos; // get floor bottom coordinate + row = -origin_y - row; + scroll_draw_row(row-1); // redraw 2rd line + scroll_draw_row(row-2); // redraw 3th line + swap_needed = true; +} + +// EXPLOSION + +byte explode_timer = 0; + +#define SPRITE_XPLODE 7 +#define SHAPE_XPLODE0 (32+10) +#define NUM_XPLODE_SHAPES 3 + +void explode(int x, byte y) { + sprite_draw(SPRITE_XPLODE, x, y, SHAPE_XPLODE0+NUM_XPLODE_SHAPES-1); + sprshad.spr_color[SPRITE_XPLODE] = 10; + explode_timer = NUM_XPLODE_SHAPES; +} + +void animate_explosion(void) { + if (explode_timer) { + if (--explode_timer == 0) { + sprshad.spr_ena &= ~(1 << SPRITE_XPLODE); + } else { + sprshad.spr_ena |= (1 << SPRITE_XPLODE); + sprshad.spr_shapes[SPRITE_XPLODE] = SHAPE_XPLODE0-1+explode_timer; + } + } +} + // ACTORS word get_floor_yy(byte level) { @@ -376,11 +456,11 @@ void draw_actor(byte i) { case WALKING: name += (a->x & 4); case JUMPING: - case FALLING: - //name = a->dir ? 16*4 : 0; + if (!a->dir) name += 5; break; + case FALLING: case CLIMBING: - //name += (a->yy & 4) ? 16*4 : 0; + if (a->yy & 4) name += 5; break; } sprite_draw(i, a->x + XOFS, screen_y, name); @@ -394,6 +474,7 @@ void refresh_actors() { sprite_clear(); for (i=0; i BOTTOM_Y/2+32 && origin_y < START_ORIGIN_Y) { + if (sprshad.spr_pos[0].y > BOTTOM_Y/2+32 + && (origin_y < START_ORIGIN_Y || scroll_fine_y)) { scroll_vert(-1); } } @@ -528,14 +610,30 @@ void move_actor(struct Actor* actor, byte joystick, bool scroll) { } } +// should we pickup an object? only player does this void pickup_object(Actor* actor) { - Floor* level = &floors[actor->level]; - byte objtype = level->objtype; - if (objtype && actor->state == WALKING) { - byte objx = level->objpos * 16 + 16 - XOFS; + Floor* floor = &floors[actor->level]; + byte objtype = floor->objtype; + // only pick up if there's an object, and if we're walking or standing + if (objtype && actor->state <= WALKING) { + byte objx = floor->objpos * 16 + 16 - XOFS; + // is the actor close to the object? if (actor->x >= objx && actor->x < objx+16) { - level->objtype = 0; - refresh_screen(); + // clear the item from the floor and redraw + floor->objtype = 0; + refresh_floor(actor->level); + // show explosion + explode(objx + XOFS, yscroll - actor->yy); + // did we hit a mine? + if (objtype == ITEM_MINE) { + // we hit a mine, fall down + fall_down(actor); + //sfx_play(SND_HIT,0); + } else { + // we picked up an object, add to score + //score = bcd_add(score, 1); + //sfx_play(SND_COIN,0); + } } } } @@ -557,8 +655,9 @@ bool check_collision(Actor* a) { // actors must be on same level // no need to apply XOFS because both sprites are offset if (a->level == b->level && - iabs(a->yy - b->yy) < 8 && - iabs(a->x - b->x) < 8) { + b->onscreen && + iabs(a->yy - b->yy) < 16 && + iabs(a->x - b->x) < 16) { return true; } } @@ -567,18 +666,6 @@ bool check_collision(Actor* a) { /// -void preview_stage() { - /* - scroll_y = floors[MAX_LEVELS-1].ypos; - while (scroll_y > 0) { - wait_vblank(); - refresh_screen(); - refresh_actors(); - scroll_y--; - } - */ -} - void draw_blimp(struct cvu_sprite* sprite) { /* sprite->name = 48; @@ -647,6 +734,7 @@ void play_scene() { fall_down(&actors[0]); } } + if (swap_needed) sprite_update(hidbuf); wait_vblank(); scroll_update(); sprite_update(visbuf); @@ -655,8 +743,6 @@ void play_scene() { blimp_pickup_scene(); } -// MAIN - // main program void main() { byte i; @@ -665,25 +751,22 @@ void main() { scroll_setup(); // set up sprites sprite_clear(); - for (i=0; i<5; i++) { + for (i=0; i +#include +#include +#include +#include + +#include "common.h" +//#link "common.c" + +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); +} + +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]; +} + +void set_pixel(byte x, byte y, byte color) { + word ofs,b,cram,sram; + byte ccol,scol; + byte val; + + if (x >= 160 || y >= 192) return; + + color &= 0xf; + // equal to background color? (value 0) + if (color == VIC.bgcolor0) { + val = 0; + } else { + cram = ((x>>2) + (y>>3)*40); + sram = cram | 0x6000; + cram |= 0xd800; + ccol = PEEK(cram); + scol = PEEK(sram); + // color RAM contains unused bits (0x10 and 0x20) + // unused in lower nibble of screen RAM? (value 2) + if (color == (scol & 0xf) || !(ccol & 0x10)) { + val = 2; + scol = (scol & 0xf0) | color; + ccol |= 0x10; + POKE(sram, scol); + // unused in upper nibble of screen RAM? (value 1) + } else if (color == (scol >> 4) || !(ccol & 0x20)) { + val = 1; + scol = (scol & 0xf) | (color << 4); + ccol |= 0x20; + POKE(sram, scol); + // all other colors in use, use color RAM + } else { + val = 3; + ccol = 0x30 | color; + } + POKE(cram, ccol); + } + + ofs = ((x>>2)*8 + (y>>3)*320) | (y&7) | 0x4000; + x &= 3; + b = PEEK(ofs) & PIXMASK[x]; + if (val) { + b |= val << PIXSHIFT[x]; + } + POKE(ofs, b); +} + +void draw_line(int x0, int y0, int x1, int y1, byte color) { + int dx = abs(x1-x0); + int sx = x0dy ? dx : -dy)>>1; + int e2; + for(;;) { + set_pixel(x0, y0, color); + if (x0==x1 && y0==y1) break; + e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} + +#pragma static-locals(push,off) +byte flood_fill(byte x, byte y, byte color) { + register byte x1 = x; + register byte x2; + register byte i; + // find left edge + while (!is_pixel(x1, y)) + --x1; + // exit if (x,y) is on a boundary + if (x1 == x) + return 1; + ++x1; + // find right edge + x2 = x+1; + while (!is_pixel(x2, y)) + ++x2; + // fill scanline + for (i=x1; i