mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-02 00:30:47 +00:00
SMS pix format (sl:); new presets
This commit is contained in:
parent
f87ff47a35
commit
138ee806cb
1026
presets/sms-sms-libcv/chr_generic.c
Normal file
1026
presets/sms-sms-libcv/chr_generic.c
Normal file
File diff suppressed because it is too large
Load Diff
521
presets/sms-sms-libcv/climber.c
Normal file
521
presets/sms-sms-libcv/climber.c
Normal file
@ -0,0 +1,521 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
//#link "chr_generic.c"
|
||||
extern const unsigned char CHR_GENERIC[8192];
|
||||
|
||||
#define XOFS -16 // sprite horiz. offset
|
||||
#define LADDER_DELTA_X 8
|
||||
|
||||
#define BGCOL CV_COLOR_BLUE
|
||||
|
||||
#define CH_BORDER 0x8f
|
||||
#define CH_FLOOR 0xf4
|
||||
#define CH_LADDER 0xd4
|
||||
#define CH_ITEM 0xc8
|
||||
#define CH_PLAYER 0xd8
|
||||
|
||||
/*{pal:222,n:16}*/
|
||||
const char PALETTE0[16] = {
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
};
|
||||
|
||||
/*{pal:222,n:16}*/
|
||||
const char PALETTE1[16] = {
|
||||
0x30, 0x00, 0x3F, 0x03,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
0x30, 0x38, 0x3E, 0x3F,
|
||||
};
|
||||
|
||||
#define NUM_SPRITE_PATTERNS 5
|
||||
#define NUM_SPRITE_STATES 4
|
||||
|
||||
///
|
||||
|
||||
typedef struct Level {
|
||||
byte ypos;
|
||||
byte height; // TODO: why does bitmask not work?
|
||||
byte gap:4;
|
||||
byte ladder1:4;
|
||||
byte ladder2:4;
|
||||
byte objtype:4;
|
||||
byte objpos:4;
|
||||
} Level;
|
||||
|
||||
#define MAX_LEVELS 32
|
||||
#define GAPSIZE 3
|
||||
|
||||
Level levels[MAX_LEVELS];
|
||||
|
||||
bool is_in_gap(byte x, byte gap) {
|
||||
if (gap) {
|
||||
byte x1 = gap*16 + 26 - XOFS;
|
||||
return (x > x1 && x < x1+GAPSIZE*8-4);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ladder_in_gap(byte x, byte gap) {
|
||||
return gap && x >= gap && x < gap+GAPSIZE*2;
|
||||
}
|
||||
|
||||
void make_levels() {
|
||||
byte i;
|
||||
byte y=0;
|
||||
Level* prevlev = &levels[0];
|
||||
for (i=0; i<MAX_LEVELS; i++) {
|
||||
Level* lev = &levels[i];
|
||||
lev->height = rndint(4,7);
|
||||
lev->ladder1 = rndint(1,14);
|
||||
lev->ladder2 = rndint(1,14);
|
||||
do {
|
||||
lev->gap = i>0 ? rndint(0,13) : 0;
|
||||
} while (ladder_in_gap(prevlev->ladder1, lev->gap) ||
|
||||
ladder_in_gap(prevlev->ladder2, lev->gap));
|
||||
lev->objtype = rndint(1,2);
|
||||
lev->objpos = rndint(1,14);
|
||||
lev->ypos = y;
|
||||
y += lev->height;
|
||||
prevlev = lev;
|
||||
}
|
||||
// top level is special
|
||||
levels[MAX_LEVELS-1].height = 15;
|
||||
levels[MAX_LEVELS-1].gap = 0;
|
||||
levels[MAX_LEVELS-1].ladder1 = 0;
|
||||
levels[MAX_LEVELS-1].ladder2 = 0;
|
||||
levels[MAX_LEVELS-1].objtype = 0;
|
||||
}
|
||||
|
||||
static byte scroll_y = 0;
|
||||
|
||||
void create_actors_on_level(byte i);
|
||||
|
||||
void draw_level_line(byte screen_y) {
|
||||
char buf[COLS*2];
|
||||
byte i;
|
||||
byte y = screen_y + scroll_y;
|
||||
for (i=0; i<MAX_LEVELS; i++) {
|
||||
Level* lev = &levels[i];
|
||||
byte dy = y - lev->ypos;
|
||||
// is this level visible on-screen?
|
||||
if (dy < lev->height) {
|
||||
if (dy == 0) {
|
||||
// draw floor
|
||||
memset(buf, CH_FLOOR, sizeof(buf));
|
||||
// draw the gap
|
||||
if (lev->gap)
|
||||
memset(buf+lev->gap*2, 0, GAPSIZE*2);
|
||||
} else {
|
||||
// draw empty space
|
||||
memset(buf, 0, sizeof(buf));
|
||||
// draw walls
|
||||
if (i < MAX_LEVELS-1) {
|
||||
buf[0] = CH_FLOOR;
|
||||
buf[COLS*2-1] = CH_FLOOR;
|
||||
}
|
||||
// draw ladders
|
||||
if (lev->ladder1) {
|
||||
buf[lev->ladder1*4] = CH_LADDER;
|
||||
buf[lev->ladder1*4+2] = CH_LADDER+2;
|
||||
}
|
||||
if (lev->ladder2) {
|
||||
buf[lev->ladder2*4] = CH_LADDER;
|
||||
buf[lev->ladder2*4+2] = CH_LADDER+2;
|
||||
}
|
||||
}
|
||||
// draw object, if it exists
|
||||
if (lev->objtype) {
|
||||
byte ch = lev->objtype*4 + CH_ITEM;
|
||||
if (dy == 1) {
|
||||
buf[lev->objpos*2] = ch+1;
|
||||
buf[lev->objpos*2+2] = ch+3;
|
||||
}
|
||||
else if (dy == 2) {
|
||||
buf[lev->objpos*2] = ch;
|
||||
buf[lev->objpos*2+2] = ch+2;
|
||||
}
|
||||
}
|
||||
// copy line to screen buffer
|
||||
cvu_memtovmemcpy(IMAGE + COLS*2*(ROWS-1) - COLS*2*screen_y, buf, sizeof(buf));
|
||||
// create actors on this level, if needed
|
||||
// (only when drawing top and bottom of screen)
|
||||
if (screen_y == 0 || screen_y == ROWS-1)
|
||||
create_actors_on_level(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_screen() {
|
||||
byte y;
|
||||
for (y=0; y<ROWS; y++) {
|
||||
draw_level_line(y);
|
||||
}
|
||||
}
|
||||
|
||||
word get_floor_yy(byte level) {
|
||||
return levels[level].ypos * 8 + 8;
|
||||
}
|
||||
|
||||
word get_ceiling_yy(byte level) {
|
||||
return (levels[level].ypos + levels[level].height) * 8 + 8;
|
||||
}
|
||||
|
||||
#define MAX_ACTORS 5
|
||||
|
||||
typedef enum ActorState {
|
||||
INACTIVE, WALKING, CLIMBING, JUMPING, FALLING
|
||||
};
|
||||
|
||||
typedef struct Actor {
|
||||
word yy;
|
||||
byte x;
|
||||
byte name;
|
||||
byte color1:4;
|
||||
byte color2:4;
|
||||
byte level;
|
||||
byte state:4;
|
||||
byte dir:1;
|
||||
byte onscreen:1;
|
||||
union {
|
||||
struct {
|
||||
sbyte yvel;
|
||||
sbyte xvel;
|
||||
} jumping;
|
||||
} u;
|
||||
} Actor;
|
||||
|
||||
Actor actors[MAX_ACTORS];
|
||||
|
||||
void create_actors_on_level(byte level_index) {
|
||||
byte actor_index = (level_index % (MAX_ACTORS-1)) + 1;
|
||||
struct Actor* a = &actors[actor_index];
|
||||
if (!a->onscreen) {
|
||||
Level *level = &levels[level_index];
|
||||
a->state = WALKING;
|
||||
a->color1 = level->ladder1;
|
||||
a->color2 = level->ladder2;
|
||||
a->name = CH_PLAYER;
|
||||
a->x = level->ladder1 ^ (level->ladder2<<3) ^ (level->gap<<6);
|
||||
a->yy = get_floor_yy(level_index);
|
||||
a->level = level_index;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_actor(byte i) {
|
||||
struct Actor* a = &actors[i];
|
||||
struct cvu_sprite4 sprite;
|
||||
int screen_y = 168 - a->yy + scroll_y*8;
|
||||
if (screen_y > 192+8 || screen_y < -18) {
|
||||
a->onscreen = 0;
|
||||
return; // offscreen vertically
|
||||
}
|
||||
sprite.name = a->name;
|
||||
switch (a->state) {
|
||||
case INACTIVE:
|
||||
a->onscreen = 0;
|
||||
return; // inactive, offscreen
|
||||
case WALKING:
|
||||
sprite.name += (a->x & 4) ? 12 : 16;
|
||||
break;
|
||||
case JUMPING:
|
||||
sprite.name += 4;
|
||||
break;
|
||||
case FALLING:
|
||||
sprite.name += 24;
|
||||
break;
|
||||
case CLIMBING:
|
||||
// TODO: animation
|
||||
sprite.name += 20;
|
||||
break;
|
||||
}
|
||||
sprite.x = a->x;
|
||||
sprite.y = screen_y;
|
||||
//sprite.tag = a->color1 | 0x80;
|
||||
sprite.x += XOFS;
|
||||
cvu_set_sprite4(SPRITES, i*2, &sprite);
|
||||
//sprite.tag ^= a->color1 ^ a->color2;
|
||||
sprite.x += 8;
|
||||
sprite.name += 2;
|
||||
cvu_set_sprite4(SPRITES, i*2+1, &sprite);
|
||||
a->onscreen = 1;
|
||||
}
|
||||
|
||||
void refresh_actors() {
|
||||
byte i;
|
||||
for (i=0; i<MAX_ACTORS; i++)
|
||||
draw_actor(i);
|
||||
}
|
||||
|
||||
void refresh_screen() {
|
||||
wait_vsync();
|
||||
draw_screen();
|
||||
refresh_actors();
|
||||
}
|
||||
|
||||
byte is_ladder_close(byte actor_x, byte ladder_pos) {
|
||||
byte ladder_x;
|
||||
if (ladder_pos == 0)
|
||||
return 0;
|
||||
ladder_x = ladder_pos * 16 + LADDER_DELTA_X;
|
||||
return ((byte)(actor_x - ladder_x) < 16) ? ladder_x : 0;
|
||||
}
|
||||
|
||||
byte get_closest_ladder(byte player_x, byte level_index) {
|
||||
Level* level = &levels[level_index];
|
||||
byte x;
|
||||
if (level_index >= MAX_LEVELS) return 0;
|
||||
x = is_ladder_close(player_x, level->ladder1);
|
||||
if (x) return x;
|
||||
x = is_ladder_close(player_x, level->ladder2);
|
||||
if (x) return x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte mount_ladder(Actor* player, signed char level_adjust) {
|
||||
byte x = get_closest_ladder(player->x, player->level + level_adjust);
|
||||
if (x) {
|
||||
player->x = x + 8;
|
||||
player->state = CLIMBING;
|
||||
player->level += level_adjust;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void check_scroll_up() {
|
||||
byte player_screen_y = cvu_vinb(SPRITES + 0); // sprite Y pos
|
||||
if (player_screen_y < 192/2-4) {
|
||||
scroll_y++;
|
||||
refresh_screen();
|
||||
check_scroll_up();
|
||||
}
|
||||
}
|
||||
|
||||
void check_scroll_down() {
|
||||
byte player_screen_y = cvu_vinb(SPRITES + 0); // sprite Y pos
|
||||
if (player_screen_y > 192/2+4 && scroll_y > 0) {
|
||||
scroll_y--;
|
||||
refresh_screen();
|
||||
check_scroll_down();
|
||||
}
|
||||
}
|
||||
|
||||
void fall_down(struct Actor* actor) {
|
||||
actor->level--;
|
||||
actor->state = FALLING;
|
||||
actor->u.jumping.xvel = 0;
|
||||
actor->u.jumping.yvel = 0;
|
||||
}
|
||||
|
||||
void move_actor(struct Actor* actor, byte joystick, bool scroll) {
|
||||
switch (actor->state) {
|
||||
|
||||
case WALKING:
|
||||
// left/right has priority over climbing
|
||||
if (joystick & CV_FIRE_0) {
|
||||
actor->state = JUMPING;
|
||||
actor->u.jumping.xvel = 0;
|
||||
actor->u.jumping.yvel = 15;
|
||||
if (joystick & CV_LEFT) actor->u.jumping.xvel = -1;
|
||||
if (joystick & CV_RIGHT) actor->u.jumping.xvel = 1;
|
||||
} else if (joystick & CV_LEFT) {
|
||||
actor->x--;
|
||||
actor->dir = 1;
|
||||
} else if (joystick & CV_RIGHT) {
|
||||
actor->x++;
|
||||
actor->dir = 0;
|
||||
} else if (joystick & CV_UP) {
|
||||
mount_ladder(actor, 0); // state -> CLIMBING
|
||||
if (scroll) check_scroll_up();
|
||||
} else if (joystick & CV_DOWN) {
|
||||
mount_ladder(actor, -1); // state -> CLIMBING, level -= 1
|
||||
if (scroll) check_scroll_down();
|
||||
}
|
||||
break;
|
||||
|
||||
case CLIMBING:
|
||||
if (joystick & CV_UP) {
|
||||
if (actor->yy >= get_ceiling_yy(actor->level)) {
|
||||
actor->level++;
|
||||
actor->state = WALKING;
|
||||
if (scroll) check_scroll_up();
|
||||
} else {
|
||||
actor->yy++;
|
||||
}
|
||||
} else if (joystick & CV_DOWN) {
|
||||
if (actor->yy <= get_floor_yy(actor->level)) {
|
||||
actor->state = WALKING;
|
||||
if (scroll) check_scroll_down();
|
||||
} else {
|
||||
actor->yy--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case JUMPING:
|
||||
case FALLING:
|
||||
actor->x += actor->u.jumping.xvel;
|
||||
actor->yy += actor->u.jumping.yvel/4;
|
||||
actor->u.jumping.yvel -= 1;
|
||||
if (actor->yy <= get_floor_yy(actor->level)) {
|
||||
actor->yy = get_floor_yy(actor->level);
|
||||
actor->state = WALKING;
|
||||
if (scroll) check_scroll_down();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// don't allow player to travel past left/right edges of screen
|
||||
if (actor->x == 0) actor->x = 255; // we wrapped around right edge
|
||||
if (actor->x < 24) actor->x = 24;
|
||||
// if player lands in a gap, they fall (switch to JUMPING state)
|
||||
if (actor->state == WALKING &&
|
||||
is_in_gap(actor->x, levels[actor->level].gap)) {
|
||||
fall_down(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void pickup_object(Actor* actor) {
|
||||
Level* level = &levels[actor->level];
|
||||
byte objtype = level->objtype;
|
||||
if (objtype && actor->state == WALKING) {
|
||||
byte objx = level->objpos * 16 + 24 - XOFS;
|
||||
if (actor->x >= objx && actor->x < objx+16) {
|
||||
level->objtype = 0;
|
||||
refresh_screen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void move_player() {
|
||||
struct cv_controller_state ctrl;
|
||||
cv_get_controller_state(&ctrl, 0);
|
||||
move_actor(&actors[0], ctrl.joystick, true);
|
||||
pickup_object(&actors[0]);
|
||||
}
|
||||
|
||||
inline byte iabs(int x) {
|
||||
return x >= 0 ? x : -x;
|
||||
}
|
||||
|
||||
bool check_collision(Actor* a) {
|
||||
byte i;
|
||||
for (i=1; i<MAX_ACTORS; i++) {
|
||||
Actor* b = &actors[i];
|
||||
// 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) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
void preview_stage() {
|
||||
scroll_y = levels[MAX_LEVELS-1].ypos;
|
||||
while (scroll_y > 0) {
|
||||
wait_vsync();
|
||||
refresh_screen();
|
||||
refresh_actors();
|
||||
scroll_y--;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_blimp(struct cvu_sprite4* sprite) {
|
||||
sprite->name = 48;
|
||||
wait_vsync();
|
||||
cvu_set_sprite4(SPRITES, 28, sprite);
|
||||
sprite->name += 4;
|
||||
sprite->x += 16;
|
||||
cvu_set_sprite4(SPRITES, 29, sprite);
|
||||
sprite->name += 4;
|
||||
sprite->x += 16;
|
||||
cvu_set_sprite4(SPRITES, 30, sprite);
|
||||
sprite->name += 4;
|
||||
sprite->x += 16;
|
||||
cvu_set_sprite4(SPRITES, 31, sprite);
|
||||
refresh_actors();
|
||||
}
|
||||
|
||||
void blimp_pickup_scene() {
|
||||
struct cvu_sprite4 sprite;
|
||||
byte player_screen_y = cvu_vinb(SPRITES + 0); // sprite Y pos
|
||||
sprite.x = actors[0].x-14;
|
||||
sprite.y = 240;
|
||||
//sprite.tag = 0x8f;
|
||||
while (sprite.y != player_screen_y-16) {
|
||||
draw_blimp(&sprite);
|
||||
sprite.x -= 48;
|
||||
sprite.y++;
|
||||
}
|
||||
while (sprite.y != 240) {
|
||||
draw_blimp(&sprite);
|
||||
sprite.x -= 48;
|
||||
sprite.y--;
|
||||
actors[0].yy++;
|
||||
}
|
||||
}
|
||||
|
||||
void play_scene() {
|
||||
byte i;
|
||||
|
||||
memset(actors, 0, sizeof(actors));
|
||||
actors[0].state = WALKING;
|
||||
actors[0].color1 = 0xf;
|
||||
actors[0].color2 = 0xb;
|
||||
actors[0].name = CH_PLAYER;
|
||||
actors[0].x = 64;
|
||||
actors[0].yy = 8;
|
||||
actors[0].level = 0;
|
||||
|
||||
create_actors_on_level(2);
|
||||
refresh_screen();
|
||||
|
||||
while (actors[0].level != MAX_LEVELS-1) {
|
||||
wait_vsync();
|
||||
refresh_actors();
|
||||
move_player();
|
||||
// move all the actors
|
||||
for (i=1; i<MAX_ACTORS; i++) {
|
||||
move_actor(&actors[i], rand(), false);
|
||||
}
|
||||
// see if the player hit another actor
|
||||
if (cv_get_sprite_collission()) {
|
||||
if (actors[0].level > 0 && check_collision(&actors[0])) {
|
||||
fall_down(&actors[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blimp_pickup_scene();
|
||||
}
|
||||
|
||||
void setup_graphics() {
|
||||
cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC));
|
||||
cvu_memtocmemcpy(0xc000, PALETTE0, 16);
|
||||
cvu_memtocmemcpy(0xc010, PALETTE1, 16);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vdp_setup();
|
||||
setup_graphics();
|
||||
cv_set_screen_active(true);
|
||||
cv_set_vint_handler(&vint_handler);
|
||||
make_levels();
|
||||
play_scene();
|
||||
}
|
125
presets/sms-sms-libcv/common.c
Normal file
125
presets/sms-sms-libcv/common.c
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
volatile uint_fast8_t vint_counter;
|
||||
|
||||
void vint_handler(void) {
|
||||
vint_counter++;
|
||||
}
|
||||
|
||||
const unsigned char reverse_lookup[16] = {
|
||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };
|
||||
|
||||
byte reverse_bits(byte n) {
|
||||
return (reverse_lookup[n&0b1111] << 4) | reverse_lookup[n>>4];
|
||||
}
|
||||
|
||||
void flip_sprite_patterns(word dest, const byte* patterns, word len) {
|
||||
word i;
|
||||
for (i=0; i<len; i++) {
|
||||
cvu_voutb(reverse_bits(*patterns++), dest++ ^ 16); // swap left/right chars
|
||||
}
|
||||
}
|
||||
|
||||
void clrscr() {
|
||||
cvu_vmemset(IMAGE, 0, COLS*ROWS);
|
||||
}
|
||||
|
||||
word getimageaddr(byte x, byte y) {
|
||||
return IMAGE + y*COLS + x;
|
||||
}
|
||||
|
||||
byte getchar(byte x, byte y) {
|
||||
return cvu_vinb(getimageaddr(x,y));
|
||||
}
|
||||
|
||||
void putchar(byte x, byte y, byte attr) {
|
||||
cvu_voutb(attr, getimageaddr(x,y));
|
||||
}
|
||||
|
||||
void putstring(byte x, byte y, const char* string) {
|
||||
while (*string) {
|
||||
putchar(x++, y, CHAR(*string++));
|
||||
}
|
||||
}
|
||||
|
||||
void delay(byte i) {
|
||||
while (i--) {
|
||||
wait_vsync();
|
||||
}
|
||||
}
|
||||
|
||||
byte rndint(byte a, byte b) {
|
||||
return ((byte)rand() % (b-a+1)) + a;
|
||||
}
|
||||
|
||||
void memset_safe(void* _dest, char ch, word size) {
|
||||
byte* dest = _dest;
|
||||
while (size--) {
|
||||
*dest++ = ch;
|
||||
}
|
||||
}
|
||||
|
||||
char in_rect(byte x, byte y, byte x0, byte y0, byte w, byte h) {
|
||||
return ((byte)(x-x0) < w && (byte)(y-y0) < h); // unsigned
|
||||
}
|
||||
|
||||
void draw_bcd_word(byte x, byte y, word bcd) {
|
||||
byte j;
|
||||
x += 3;
|
||||
for (j=0; j<4; j++) {
|
||||
putchar(x, y, CHAR('0'+(bcd&0xf)));
|
||||
x--;
|
||||
bcd >>= 4;
|
||||
}
|
||||
}
|
||||
|
||||
// add two 16-bit BCD values
|
||||
word bcd_add(word a, word b) __naked {
|
||||
a; b; // to avoid warning
|
||||
__asm
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp
|
||||
ld a,4 (ix)
|
||||
add a, 6 (ix)
|
||||
daa
|
||||
ld c,a
|
||||
ld a,5 (ix)
|
||||
adc a, 7 (ix)
|
||||
daa
|
||||
ld b,a
|
||||
ld l, c
|
||||
ld h, b
|
||||
pop ix
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
||||
void vdp_setup() {
|
||||
cv_set_screen_active(false);
|
||||
cv_set_screen_mode(CV_SCREENMODE_STANDARD);
|
||||
cv_set_image_table(IMAGE);
|
||||
cv_set_character_pattern_t(PATTERN);
|
||||
cv_set_color_table(COLOR);
|
||||
cv_set_sprite_pattern_table(SPRITE_PATTERNS);
|
||||
cv_set_sprite_attribute_table(SPRITES);
|
||||
cv_set_sprite_big(true);
|
||||
}
|
||||
|
||||
void set_shifted_pattern(const byte* src, word dest, byte shift) {
|
||||
byte y;
|
||||
for (y=0; y<8; y++) {
|
||||
byte a = src[y+8];
|
||||
byte b = src[y];
|
||||
cvu_voutb(a>>shift, dest);
|
||||
cvu_voutb(b>>shift | a<<(8-shift), dest+8);
|
||||
cvu_voutb(b<<(8-shift), dest+16);
|
||||
dest++;
|
||||
}
|
||||
}
|
72
presets/sms-sms-libcv/common.h
Normal file
72
presets/sms-sms-libcv/common.h
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
#ifndef _CV_COMMON_H
|
||||
#define _CV_COMMON_H
|
||||
|
||||
/* VRAM map
|
||||
0x0000 - 0x17ff character pattern table
|
||||
0x1800 - 0x1aff image table
|
||||
0x2000 - 0x37ff color table
|
||||
0x3800 - 0x3bff sprite pattern table
|
||||
0x3c00 - 0x3fff sprite attribute table
|
||||
*/
|
||||
|
||||
#define PATTERN ((const cv_vmemp)0x0000)
|
||||
#define IMAGE ((const cv_vmemp)0x1800)
|
||||
#define COLOR ((const cv_vmemp)0x2000)
|
||||
#define SPRITE_PATTERNS ((const cv_vmemp)0x3800)
|
||||
#define SPRITES ((const cv_vmemp)0x3c00)
|
||||
|
||||
#define COLS 32
|
||||
#define ROWS 24
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
|
||||
#ifndef CV_SMS
|
||||
uintptr_t __at(0x6a) font_bitmap_a;
|
||||
uintptr_t __at(0x6c) font_bitmap_0;
|
||||
#else
|
||||
extern char font_bitmap_a[];
|
||||
extern char font_bitmap_0[];
|
||||
#endif
|
||||
|
||||
#define COLOR_FGBG(fg,bg) (((fg)<<4)|(bg))
|
||||
#define COLOR_FG(fg) (((fg)<<4))
|
||||
|
||||
#define LOCHAR 0x20
|
||||
#define HICHAR 0xff
|
||||
|
||||
#define CHAR(ch) (ch-LOCHAR)
|
||||
|
||||
#define wait_vsync() __asm__("halt")
|
||||
|
||||
extern volatile uint_fast8_t vint_counter;
|
||||
|
||||
extern void vint_handler(void);
|
||||
extern byte reverse_bits(byte n);
|
||||
extern void flip_sprite_patterns(word dest, const byte* patterns, word len);
|
||||
|
||||
extern char cursor_x;
|
||||
extern char cursor_y;
|
||||
|
||||
extern void clrscr();
|
||||
|
||||
extern word getimageaddr(byte x, byte y);
|
||||
extern byte getchar(byte x, byte y);
|
||||
extern void putchar(byte x, byte y, byte attr);
|
||||
extern void putstring(byte x, byte y, const char* string);
|
||||
extern void delay(byte i);
|
||||
extern byte rndint(byte a, byte b);
|
||||
|
||||
extern void memset_safe(void* _dest, char ch, word size);
|
||||
extern char in_rect(byte x, byte y, byte x0, byte y0, byte w, byte h);
|
||||
// print 4-digit BCD value
|
||||
extern void draw_bcd_word(byte x, byte y, word bcd);
|
||||
// add two 16-bit BCD values
|
||||
extern word bcd_add(word a, word b);
|
||||
|
||||
extern void vdp_setup();
|
||||
extern void set_shifted_pattern(const byte* src, word dest, byte shift);
|
||||
|
||||
#endif
|
BIN
presets/sms-sms-libcv/generic.chr4
Normal file
BIN
presets/sms-sms-libcv/generic.chr4
Normal file
Binary file not shown.
@ -2,56 +2,102 @@
|
||||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#ifdef CV_SMS
|
||||
//#link "fonts.s"
|
||||
extern uintptr_t font_bitmap_a[];
|
||||
extern uintptr_t font_bitmap_0[];
|
||||
#endif
|
||||
|
||||
#define wait_vsync() __asm__("halt")
|
||||
|
||||
#define PATTERN 0x0000 // 256*8 = 2048 bytes
|
||||
#define IMAGE 0x0800 // 32*24 = 768 bytes
|
||||
#define IMAGE 0x2000 // 32*24 = 768 bytes
|
||||
#define COLOR 0x0b00 // 32 bytes
|
||||
#define SPRITE_PATTERNS 0x3800 // 32*32 = 1024 bytes
|
||||
#define SPRITES 0x3c00 // 4*32 = 128 bytes
|
||||
|
||||
const char PALETTE[32] = {
|
||||
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
/*{pal:222,n:16}*/
|
||||
const char PALETTE0[16] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x0D,
|
||||
};
|
||||
|
||||
/*{w:8,h:8,bpp:1,count:1,brev:1,np:4,pofs:1,sl:4}*/
|
||||
const char PATTERNS[32] = {
|
||||
0x1, 0x2, 0x3, 0x4,
|
||||
0x5, 0x6, 0x7, 0x8,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x55, 0x66, 0x77, 0xff,
|
||||
0xc0, 0xc0, 0xc0, 0xc0,
|
||||
0x5, 0x6, 0x7, 0x8,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
/*{pal:222,n:16}*/
|
||||
const char PALETTE1[16] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x3F,
|
||||
};
|
||||
|
||||
/*{w:8,h:8,bpp:1,count:2,brev:1,np:4,pofs:1,sl:4}*/
|
||||
const char PATTERNS[64] = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x56, 0x7E, 0x56, 0x56,
|
||||
0x7E, 0x7E, 0x7E, 0x7E,
|
||||
0x62, 0x62, 0x62, 0x62,
|
||||
0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x18, 0x3E, 0x18, 0x3E,
|
||||
0x18, 0x7F, 0x00, 0x7F,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x55, 0x66, 0x77, 0xFF,
|
||||
0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0x05, 0x06, 0x07, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
void expand_monobitmap(const char* src, int count) {
|
||||
while (count--) {
|
||||
char b = *src++;
|
||||
cv_voutb(b);
|
||||
cv_voutb(b);
|
||||
cv_voutb(b);
|
||||
cv_voutb(b);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_graphics() {
|
||||
cv_set_screen_mode(CV_SCREENMODE_4);
|
||||
/*
|
||||
cv_set_colors(0x2, 0x5);
|
||||
cv_set_character_pattern_t(PATTERN | 0x3000);
|
||||
cv_set_image_table(IMAGE | 0x400);
|
||||
cv_set_sprite_attribute_table(SPRITES);
|
||||
/*
|
||||
cvu_vmemset(0, 0, 0x4000);
|
||||
cv_set_colors(0x2, 0x5);
|
||||
cv_set_color_table(COLOR | 0xfff);
|
||||
cv_set_sprite_pattern_table(SPRITE_PATTERNS | 0x1800);
|
||||
cv_set_sprite_attribute_table(SPRITES);
|
||||
*/
|
||||
cvu_memtovmemcpy(PATTERN, PATTERNS, 32);
|
||||
cvu_memtocmemcpy(0xc000, PALETTE, 32);
|
||||
cv_set_write_vram_address(PATTERN + '0'*32);
|
||||
expand_monobitmap(font_bitmap_0, (128-48)*8);
|
||||
cvu_memtovmemcpy(PATTERN+32, PATTERNS, 32);
|
||||
cvu_memtocmemcpy(0xc000, PALETTE0, 16);
|
||||
cvu_memtocmemcpy(0xc010, PALETTE1, 16);
|
||||
}
|
||||
|
||||
void show_text() {
|
||||
cvu_vmemset(IMAGE, 0, 32*24);
|
||||
cvu_memtovmemcpy(IMAGE + 1, "Hello Professor Falken", 22);
|
||||
cvu_vmemset(IMAGE, 0, 32*28);
|
||||
cvu_memtovmemcpy(IMAGE, "H e l l o P r o f e s s o r F a l k e n ", 22*2);
|
||||
cv_voutb(0x01);
|
||||
cv_voutb(0x00);
|
||||
}
|
||||
|
||||
void main() {
|
||||
char i=0;
|
||||
struct cvu_sprite4 sprite;
|
||||
setup_graphics();
|
||||
show_text();
|
||||
cv_set_screen_active(true);
|
||||
while (1) {
|
||||
// cvu_vmemset(COLOR, i++, 8); // set color for chars 0-63
|
||||
wait_vsync();
|
||||
i++;
|
||||
cv_set_hscroll(i);
|
||||
cv_set_vscroll(i);
|
||||
sprite.y = i;
|
||||
sprite.x = i;
|
||||
sprite.name = 1;
|
||||
cvu_set_sprite4(SPRITES, 0, &sprite);
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,9 @@ function convertImagesToWords(images:Uint8Array[], fmt:PixelEditorImageFormat) :
|
||||
var pofs = fmt.pofs || wordsperline*height*count;
|
||||
var skip = fmt.skip || 0;
|
||||
var words;
|
||||
if (bitsperword <= 8)
|
||||
if (nplanes > 0 && fmt.sl) // TODO?
|
||||
words = new Uint8Array(wordsperline*height*count);
|
||||
else if (bitsperword <= 8)
|
||||
words = new Uint8Array(wordsperline*height*count*nplanes);
|
||||
else
|
||||
words = new Uint32Array(wordsperline*height*count*nplanes);
|
||||
|
@ -86,7 +86,8 @@ inline void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struc
|
||||
|
||||
// Write sprite to display memory (in mode 4). Use the location of the sprite table as base. number should be in [0, 63].
|
||||
#ifdef CV_SMS
|
||||
inline void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite)
|
||||
/* TODO: used to be inline, but sdcc barfs */
|
||||
void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite)
|
||||
{
|
||||
cvu_voutb(sprite->y, base + number);
|
||||
cv_set_write_vram_address(base + 0x80 + number * 2);
|
||||
|
@ -69,5 +69,6 @@ describe('Pixel editor', function() {
|
||||
var words3 = pixed.parseHexWords(datastr3);
|
||||
assert.deepEqual(words3, [31]);
|
||||
assert.equal(datastr3, pixed.replaceHexWords(datastr3, pixed.parseHexWords(datastr3)));
|
||||
// TODO: test (nplanes > 0 && fmt.sl)
|
||||
});
|
||||
});
|
||||
|
11
tools/nes2sms.py
Normal file
11
tools/nes2sms.py
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
import sys
|
||||
|
||||
chr = open(sys.argv[1],'rb').read()
|
||||
out = open('outsms.bin','wb')
|
||||
for i in range(0,len(chr),16):
|
||||
for y in range(0,8):
|
||||
arr = [ ord(chr[i+y]), ord(chr[i+8+y]), 0, 0 ]
|
||||
out.write(bytearray(arr))
|
||||
out.close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user