diff --git a/presets/coleco/common.c b/presets/coleco/common.c index 41877c4c..5b00d15d 100644 --- a/presets/coleco/common.c +++ b/presets/coleco/common.c @@ -5,13 +5,41 @@ #include "common.h" -/* Unified common code for libcv platforms (coleco, msx-libcv, sms-sg1000-libcv, - sms-sms-libcv, sms-gg-libcv). Differences are selected by the CV_CV / CV_MSX / - CV_SMS defines (set by the platform) plus CV_MODE4 for SMS/GG mode-4 builds. +/* Unified common code for libcv platforms. + Differences are selected by the CV_CV / CV_MSX / CV_SMS defines + (set by the platform) plus CV_MODE4 for SMS/GG mode-4 builds. Keep this file identical across those preset directories. */ volatile uint_fast8_t vint_counter; +#if defined(CV_MODE4) +// current name-table attribute (palette/flip/priority) used for text output +byte text_attr = 0; + +// default mode-4 palette: entries 0-15 are the background (tile) palette, +// entries 16-31 are the sprite palette. CHR_GENERIC glyphs use colors 0-3. +#if defined(__PLATFORM_SMS_GG_LIBCV__) +#define PALCOL(r,g,b) ((unsigned short)(((b)*5)<<8 | ((g)*5)<<4 | ((r)*5))) +const unsigned short DEFAULT_PALETTE[32] = { +#else +#define PALCOL(r,g,b) ((unsigned char)(((b)<<4) | ((g)<<2) | (r))) +const unsigned char DEFAULT_PALETTE[32] = { +#endif + PALCOL(0,0,0), PALCOL(3,3,3), PALCOL(3,3,0), PALCOL(1,3,1), + PALCOL(0,0,3), PALCOL(3,0,0), PALCOL(3,0,3), PALCOL(0,3,3), + PALCOL(2,2,2), PALCOL(1,1,1), PALCOL(3,1,1), PALCOL(3,3,1), + PALCOL(1,1,3), PALCOL(2,0,0), PALCOL(0,2,0), PALCOL(0,0,2), + PALCOL(0,0,0), PALCOL(3,3,3), PALCOL(3,3,0), PALCOL(3,0,0), + PALCOL(0,3,0), PALCOL(0,0,3), PALCOL(3,0,3), PALCOL(0,3,3), + PALCOL(2,2,2), PALCOL(3,1,1), PALCOL(1,3,1), PALCOL(1,1,3), + PALCOL(2,0,0), PALCOL(0,2,0), PALCOL(0,0,2), PALCOL(1,1,1), +}; + +void set_default_palette() { + cvu_memtocmemcpy(0xc000, DEFAULT_PALETTE, sizeof(DEFAULT_PALETTE)); +} +#endif + void vint_handler(void) { vint_counter++; } @@ -39,7 +67,12 @@ void clrscr() { } word getimageaddr(byte x, byte y) { +#if defined(CV_MODE4) + // mode 4: two bytes per cell (tile + attribute) + return IMAGE + y*ROWSTRIDE + x*2; +#else return IMAGE + y*ROWSTRIDE + x; +#endif } byte getcharxy(byte x, byte y) { @@ -47,7 +80,13 @@ byte getcharxy(byte x, byte y) { } void putcharxy(byte x, byte y, byte attr) { +#if defined(CV_MODE4) + cv_vmemp addr = getimageaddr(x,y); + cvu_voutb(attr, addr); + cvu_voutb(text_attr, addr+1); +#else cvu_voutb(attr, getimageaddr(x,y)); +#endif } void putstringxy(byte x, byte y, const char* string) { @@ -57,18 +96,7 @@ void putstringxy(byte x, byte y, const char* string) { } #if defined(CV_MODE4) -// mode 4 aliases (same functions, shorter names) -byte getchar(byte x, byte y) { - return getcharxy(x, y); -} - -void putchar(byte x, byte y, byte attr) { - putcharxy(x, y, attr); -} - -void putstring(byte x, byte y, const char* string) { - putstringxy(x, y, string); -} +// mode 4 uses the same putcharxy()/putstringxy()/getcharxy() API as other modes. #endif void delay(byte i) { @@ -130,8 +158,6 @@ void vdp_setup() { cv_set_screen_mode(CV_SCREENMODE_4_224); cv_set_character_pattern_t(PATTERN | 0x3000); cv_set_image_table(IMAGE | 0x400); -// cv_set_color_table(COLOR | 0xfff); -// cv_set_sprite_pattern_table(SPRITE_PATTERNS | 0x1800); #else cv_set_screen_mode(CV_SCREENMODE_STANDARD); cv_set_image_table(IMAGE); @@ -145,6 +171,7 @@ void vdp_setup() { copy_default_character_set(); cvu_vmemset(COLOR, 0xf1, 32); #endif + cvu_vmemset(SPRITES, 0xff, 0x400); cv_set_sprite_attribute_table(SPRITES); cv_set_sprite_big(true); } diff --git a/presets/coleco/common.h b/presets/coleco/common.h index 12edfc74..57c639ef 100644 --- a/presets/coleco/common.h +++ b/presets/coleco/common.h @@ -67,12 +67,8 @@ extern char font_bitmap_0[]; #define COLOR_FG(fg) (((fg)<<4)) #ifndef LOCHAR -#if defined(CV_MODE4) -#define LOCHAR 0x20 -#else #define LOCHAR 0x0 #endif -#endif #define CHAR(ch) (ch-LOCHAR) @@ -94,10 +90,10 @@ extern byte getcharxy(byte x, byte y); extern void putcharxy(byte x, byte y, byte attr); extern void putstringxy(byte x, byte y, const char* string); #if defined(CV_MODE4) -// mode 4 aliases (same functions, shorter names) -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); +// name-table attribute (palette/flip/priority) used by putcharxy()/putstringxy() +extern byte text_attr; +// load the default 32-entry mode-4 palette into CRAM +extern void set_default_palette(); #endif extern void delay(byte i); extern byte rndint(byte a, byte b); diff --git a/presets/sms-sms-libcv/common.c b/presets/sms-sms-libcv/common.c deleted file mode 120000 index ce249516..00000000 --- a/presets/sms-sms-libcv/common.c +++ /dev/null @@ -1 +0,0 @@ -../coleco/common.c \ No newline at end of file diff --git a/presets/sms-sms-libcv/common.c b/presets/sms-sms-libcv/common.c new file mode 100644 index 00000000..cedf6266 --- /dev/null +++ b/presets/sms-sms-libcv/common.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include + +#include "common.h" + +/* Unified common code for libcv platforms. + Differences are selected by the CV_CV / CV_MSX / CV_SMS defines + (set by the platform) plus CV_MODE4 for SMS/GG mode-4 builds. + Keep this file identical across those preset directories. */ + +volatile uint_fast8_t vint_counter; + +#if defined(CV_MODE4) +// current name-table attribute (palette/flip/priority) used for text output +byte text_attr = 0; + +// default mode-4 palette: entries 0-15 are the background (tile) palette, +// entries 16-31 are the sprite palette. CHR_GENERIC glyphs use colors 0-3. +#if defined(__PLATFORM_SMS_GG_LIBCV__) +/*{pal:444,n:32}*/ +const unsigned short DEFAULT_PALETTE[32] = { + 0x000, 0x00F, 0x0F0, 0x0FF, 0xF00, 0xF0F, 0xFF0, 0xFFF, + 0x555, 0x55F, 0xFA5, 0x5AF, 0xAA0, 0xAFA, 0xFAF, 0xAFF, + 0x000, 0x00F, 0x0F0, 0x0FF, 0xF00, 0xF0F, 0xFF0, 0xFFF, + 0x555, 0x55F, 0xFA5, 0x5AF, 0xAA0, 0xAFA, 0xFAF, 0xAFF +}; +#else +/*{pal:222,n:32}*/ +const unsigned char DEFAULT_PALETTE[32] = { + 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, + 0x15, 0x17, 0x39, 0x1B, 0x28, 0x2E, 0x3B, 0x2F, + 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, + 0x15, 0x17, 0x39, 0x1B, 0x28, 0x2E, 0x3B, 0x2F, +}; +#endif + +void set_default_palette() { + cvu_memtocmemcpy(0xc000, DEFAULT_PALETTE, sizeof(DEFAULT_PALETTE)); +} +#endif + +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>= 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); +#if defined(CV_MODE4) + cv_set_screen_mode(CV_SCREENMODE_4_224); + cv_set_character_pattern_t(PATTERN | 0x3000); + cv_set_image_table(IMAGE | 0x400); +#else + 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); + // load the default font and set a visible default color (white on black). + // the MSX startup code does this for us, but the ColecoVision and + // SG-1000 leave VRAM zeroed -- without this, putstringxy() output is + // invisible (blank pattern table) and the color table is transparent. + copy_default_character_set(); + cvu_vmemset(COLOR, 0xf1, 32); +#endif + cvu_vmemset(SPRITES, 0xff, 0x400); + 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++; + } +} + +#if !defined(CV_MODE4) +void copy_default_character_set() { +#ifdef CV_MSX + static byte __at(0xf91f) CGPNT; + static byte* __at(0xf920) CGADDR; + cvu_memtovmemcpy(PATTERN, CGADDR, 256*8); +#else + cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - '0'*8), 256*8); +#endif +} +#endif diff --git a/presets/sms-sms-libcv/common.h b/presets/sms-sms-libcv/common.h deleted file mode 120000 index d69f50fa..00000000 --- a/presets/sms-sms-libcv/common.h +++ /dev/null @@ -1 +0,0 @@ -../coleco/common.h \ No newline at end of file diff --git a/presets/sms-sms-libcv/common.h b/presets/sms-sms-libcv/common.h new file mode 100644 index 00000000..57c639ef --- /dev/null +++ b/presets/sms-sms-libcv/common.h @@ -0,0 +1,115 @@ + +#ifndef _CV_COMMON_H +#define _CV_COMMON_H + +/* Unified common header for libcv platforms. + The build defines one of: CV_CV (ColecoVision), CV_MSX, CV_SMS (SG-1000/SMS/Game Gear). + CV_MODE4 is defined for SMS/GG mode-4 builds (2 bytes per tile, 32x28). + Keep this file identical across the coleco, msx-libcv, sms-sg1000-libcv, + sms-sms-libcv and sms-gg-libcv preset directories. */ + +#if defined(CV_MODE4) +/* VRAM map (mode 4) + 0x0000 - 0x3fff character pattern table + 0x3000 - 0x36ff image table + 0x3c00 - 0x3fff sprite attribute table */ +#define PATTERN ((const cv_vmemp)0x0000) +#define IMAGE ((const cv_vmemp)0x3000) +#define SPRITES ((const cv_vmemp)0x3c00) +#else +/* 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) +#endif + +#ifndef COLS +#define COLS 32 +#endif + +#ifndef ROWS +#if defined(CV_MODE4) +#define ROWS 28 +#else +#define ROWS 24 +#endif +#endif + +/* bytes per row in the name table (mode 4 has a color byte per tile) */ +#if defined(CV_MODE4) +#define ROWSTRIDE (COLS*2) +#else +#define ROWSTRIDE COLS +#endif + +typedef unsigned char byte; +typedef signed char sbyte; +typedef unsigned short word; + +#ifdef CV_CV +uintptr_t __at(0x6a) font_bitmap_a; +uintptr_t __at(0x6c) font_bitmap_0; +#endif + +#ifdef CV_SMS +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)) + +#ifndef LOCHAR +#define LOCHAR 0x0 +#endif + +#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 getcharxy(byte x, byte y); +extern void putcharxy(byte x, byte y, byte attr); +extern void putstringxy(byte x, byte y, const char* string); +#if defined(CV_MODE4) +// name-table attribute (palette/flip/priority) used by putcharxy()/putstringxy() +extern byte text_attr; +// load the default 32-entry mode-4 palette into CRAM +extern void set_default_palette(); +#endif +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); + +#if !defined(CV_MODE4) +extern void copy_default_character_set(); +#endif + +#endif diff --git a/presets/sms-sms-libcv/cursorsmooth.c b/presets/sms-sms-libcv/cursorsmooth.c new file mode 100644 index 00000000..bbac56e9 --- /dev/null +++ b/presets/sms-sms-libcv/cursorsmooth.c @@ -0,0 +1,171 @@ +/* +This demo animates two 16 x 16 sprites. +It also uses the collision detection bit. + +Ported to the Sega VDP's mode 4: each 8x16 sprite is +built from two 8x8 pattern tiles, and a 16x16 cursor is +two sprites side by side (a "metasprite"). +*/ + +#include +#include +#include +#include + +#include "common.h" +//#link "common.c" +//#link "chr_generic.c" + +extern const unsigned char CHR_GENERIC[8192]; + +// tile number of the cursor's top-left 8x8 tile +#define SPR_CURSOR 0x80 +// inverted cursor used to show collision (SPR_CURSOR+4) +#define SPR_CURSOR_HIT (SPR_CURSOR+4) + +// 16x16 monochrome cursor (a crosshair), 2 bytes per row +static const uint8_t cursor_mono[16*2] = { + 0x00, 0x00, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0xff, 0xff, + 0xff, 0xff, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x01, 0x80, + 0x00, 0x00, +}; + +// Expand a 16x16 mono bitmap into four mode-4 8x8 tiles +// (top-left, bottom-left, top-right, bottom-right). +// Each tile is 8 rows of 4 plane bytes; we use plane 0 +// so the sprites are drawn in color 1 of the sprite palette. +void expand_cursor(word dest, byte invert) { + byte r; + for (r=0; r<16; r++) { + byte left = cursor_mono[r*2]; + byte right = cursor_mono[r*2+1]; + byte half = r >> 3; // 0 = top half, 1 = bottom half + word a = dest + half*32 + (r & 7)*4; + if (invert) { left = ~left; right = ~right; } + cvu_voutb(left, a); + cvu_voutb(0, a+1); + cvu_voutb(0, a+2); + cvu_voutb(0, a+3); + cvu_voutb(right, a+2*32); + cvu_voutb(0, a+2*32+1); + cvu_voutb(0, a+2*32+2); + cvu_voutb(0, a+2*32+3); + } +} + +void setup_graphics() { + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + set_default_palette(); + // build the normal and inverted cursor sprites + expand_cursor(PATTERN + SPR_CURSOR*32, 0); + expand_cursor(PATTERN + SPR_CURSOR_HIT*32, 1); +} + +// Set all sprites offscreen. +void set_sprites_offscreen() { + struct cvu_sprite4 s; + byte i; + s.x = 0; + s.y = 240; // set offscreen + s.name = 0; + for (i=0; i<64; i++) { + cvu_set_sprite4(SPRITES, i, &s); + } +} + +// Move a cursor with the specified controller. +// The struct stores the top-left corner of the 16x16 cursor. +void move_cursor(struct cvu_sprite4 *s, int controller) { + int x, y; + struct cv_controller_state cs; + + // Read the game controller state. + cv_get_controller_state(&cs, controller); + + // Copy the sprite X and Y coordinates to local variables. + x = s->x; + y = s->y; + + // Move one pixel in the direction the joystick is pointed. + if (cs.joystick & CV_RIGHT) x++; + if (cs.joystick & CV_LEFT) x--; + if (cs.joystick & CV_DOWN) y++; + if (cs.joystick & CV_UP) y--; + + // Make sure cursor doesn't leave the screen. + if (x < 0) x = 0; + if (x > 231) x = 231; + if (y < 0) y = 0; + if (y > 151) y = 151; + + // Update the cursor struct in CPU RAM. + s->x = x; + s->y = y; +} + +// Write a 16x16 cursor as two 8x16 sprites. +void draw_cursor(byte index, struct cvu_sprite4 *s) { + struct cvu_sprite4 right; + right.y = s->y; + right.x = s->x + 8; + right.name = s->name + 2; + cvu_set_sprite4(SPRITES, index, s); + cvu_set_sprite4(SPRITES, index+1, &right); +} + +void main(void) { + struct cvu_sprite4 s; // The sprite used for the player cursor. + struct cvu_sprite4 s2; // The sprite used for the target cursor. + byte name; + + vdp_setup(); + setup_graphics(); + + cv_set_sprite_magnification(false); // no sprite magnification + cv_set_sprite_big(true); // 8x16 pixel sprites. + + // Set all sprites offscreen initially. + // This ensures they won't set the collision bit. + set_sprites_offscreen(); + + // Set attributes for cursor 0. + s.x = 60; + s.y = 60; + s.name = SPR_CURSOR; + // Set attributes for cursor 1. + s2.x = 120; + s2.y = 60; + s2.name = SPR_CURSOR; + + // Turn on video display. + cv_set_screen_active(true); + + for(;;) + { + // Wait for VBLANK (next frame). + wait_vsync(); + // Use the inverted cursor if there was a collision last frame. + name = cv_get_sprite_collission() ? SPR_CURSOR_HIT : SPR_CURSOR; + // Move both cursors by their corresponding joystick. + move_cursor(&s, 0); + move_cursor(&s2, 1); + s.name = name; + s2.name = name; + // Update VRAM with new sprite records. + draw_cursor(0, &s); + draw_cursor(2, &s2); + } +} diff --git a/presets/sms-sms-libcv/hello.c b/presets/sms-sms-libcv/hello.c new file mode 100644 index 00000000..5e2890ac --- /dev/null +++ b/presets/sms-sms-libcv/hello.c @@ -0,0 +1,93 @@ +/* +This is a demonstration of integrating the C +standard I/O (stdio) functions with the display, +so that standard functions like printf() can be used. + +It has been ported to the Sega VDP's mode 4 text mode. +*/ + +#include +#include +#include +#include +#include + +#include "common.h" +//#link "common.c" +//#link "chr_generic.c" + +extern const unsigned char CHR_GENERIC[8192]; + +char cursor_x; // current cursor column +char cursor_y; // current cursor row + +void setup_graphics() { + // copy the font/tileset into the character pattern table + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + // load the default mode-4 palette + set_default_palette(); + cv_set_colors(CV_COLOR_BLACK, CV_COLOR_BLACK); +} + +void setup_stdio() { + cursor_x = 0; + cursor_y = 0; + clrscr(); +} + +// scroll the screen upward, by copying each row +// of VRAM to its previous row. +void scrollup() { + char buf[ROWSTRIDE]; + char y; + for (y=0; y= ROWS-1) { + scrollup(); + } else { + cursor_y++; + } +} + +// write a character to the screen. +int putchar(int ch) { + switch (ch) { + case '\n': + newline(); // move cursor to next line + case '\r': + cursor_x = 0; // move cursor to start of line + return 0; + } + // output character (tile) + attribute to the name table + putcharxy(cursor_x, cursor_y, ch); + // move cursor to right, going to next line if necessary + cursor_x++; + if (cursor_x >= COLS) { + newline(); + cursor_x = 0; + } + return ch; +} + +void main() { + unsigned char byteval = 123; + signed char charval = 123; + short shortval = 12345; + + vdp_setup(); + setup_graphics(); + setup_stdio(); + cv_set_screen_active(true); + printf("HELLO WORLD!\n"); + while (1) { + printf("char %d byte %u sh %d\n", + charval++, byteval++, shortval++); + } +} diff --git a/presets/sms-sms-libcv/musicplayer.c b/presets/sms-sms-libcv/musicplayer.c new file mode 100644 index 00000000..8fbe562d --- /dev/null +++ b/presets/sms-sms-libcv/musicplayer.c @@ -0,0 +1,114 @@ + +/* +Demonstrates playing multi-voice music on the SN76489A PSG +using the CVLib functions. + +Similar to the music example in "Making Arcade Games in C". +*/ + +#include +#include +#include +#include + +//#link "common.c" +//#link "chr_generic.c" +#include "common.h" + +extern const unsigned char CHR_GENERIC[8192]; + +// +// MUSIC ROUTINES +// + +void music_start(const byte* music); +void music_update(); + +// Namespace(bias=0, freq=1789772.5, length=64, maxbits=15.0, upper=49) +// 437.0 459.515928524 49 +const int note_table[64] = { +17356, 32764, 30926, 29190, 27551, 26005, 24546, 23168, 21868, 20640, 19482, 18388, 17356, 32765, 30926, 29190, 27552, 26005, 24546, 23168, 21868, 20640, 19482, 18389, 17357, 16382, 15463, 14595, 13776, 13003, 12273, 11584, 10934, 10320, 9741, 9194, 8678, 8191, 7731, 7298, 6888, 6501, 6136, 5792, 5467, 5160, 4871, 4597, 4339, 4096, 3866, 3649, 3444, 3251, 3068, 2896, 2733, 2580, 2435, 2299, 2170, 2048, 1933, 1824, }; + +struct { + byte volume; +} voice[3]; + +byte music_index = 0; +byte cur_duration = 0; +byte num_voices = 3; + +static const byte* music_ptr = NULL; + +inline byte next_music_byte() { + return *music_ptr++; +} + +void music_update() { + byte ch; + byte freech = 0; + for (ch=0; ch +#include +#include +#include + +#include "common.h" +//#link "common.c" +//#link "chr_generic.c" + +extern const unsigned char CHR_GENERIC[8192]; + +////////// GAME DATA + +typedef struct { + byte x; + byte y; + byte dir; + word score; + char head_attr; + char tail_attr; + char collided:1; + char human:1; +} Player; + +Player players[2]; + +byte credits = 0; +byte frames_per_move; + +#define START_SPEED 12 +#define MAX_SPEED 5 +#define MAX_SCORE 7 + +/////////// + +const char BOX_CHARS[8] = { + CHAR('+'), CHAR('+'), CHAR('+'), CHAR('+'), + CHAR('-'), CHAR('-'), CHAR('!'), CHAR('!') }; + +void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) { + byte x1 = x; + putcharxy(x, y, chars[2]); + putcharxy(x2, y, chars[3]); + putcharxy(x, y2, chars[0]); + putcharxy(x2, y2, chars[1]); + while (++x < x2) { + putcharxy(x, y, chars[5]); + putcharxy(x, y2, chars[4]); + } + while (++y < y2) { + putcharxy(x1, y, chars[6]); + putcharxy(x2, y, chars[7]); + } +} + +void draw_playfield() { + draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS); + putstringxy(0,0,"Plyr1:"); + putstringxy(20,0,"Plyr2:"); + putcharxy(7,0,CHAR(players[0].score+'0')); + putcharxy(27,0,CHAR(players[1].score+'0')); +} + +typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t; +const char DIR_X[4] = { 1, 0, -1, 0 }; +const char DIR_Y[4] = { 0, 1, 0, -1 }; + +void init_game() { + memset(players, 0, sizeof(players)); + players[0].head_attr = CHAR('1'); + players[1].head_attr = CHAR('2'); + players[0].tail_attr = CHAR('@'); + players[1].tail_attr = CHAR('%'); + frames_per_move = START_SPEED; +} + +void reset_players() { + players[0].x = players[0].y = 5; + players[0].dir = D_RIGHT; + players[1].x = 25; + players[1].y = 19; + players[1].dir = D_LEFT; + players[0].collided = players[1].collided = 0; +} + +void draw_player(Player* p) { + putcharxy(p->x, p->y, p->head_attr); +} + +void move_player(Player* p) { + putcharxy(p->x, p->y, p->tail_attr); + p->x += DIR_X[p->dir]; + p->y += DIR_Y[p->dir]; + if (getcharxy(p->x, p->y) != 0) + p->collided = 1; + draw_player(p); +} + +void human_control(Player* p) { + byte dir = 0xff; + struct cv_controller_state cs; + cv_get_controller_state(&cs, 0); // Read the controller. + if (!p->human) return; + if (cs.joystick & CV_LEFT) dir = D_LEFT; + if (cs.joystick & CV_RIGHT) dir = D_RIGHT; + if (cs.joystick & CV_UP) dir = D_UP; + if (cs.joystick & CV_DOWN) dir = D_DOWN; + // don't let the player reverse + if (dir < 0x80 && dir != (p->dir ^ 2)) { + p->dir = dir; + } +} + +byte ai_try_dir(Player* p, dir_t dir, byte shift) { + byte x,y; + dir &= 3; + x = p->x + (DIR_X[dir] << shift); + y = p->y + (DIR_Y[dir] << shift); + if (x < 29 && y < 27 && getcharxy(x, y) == 0) { + p->dir = dir; + return 1; + } else { + return 0; + } +} + +void ai_control(Player* p) { + dir_t dir; + if (p->human) return; + dir = p->dir; + if (!ai_try_dir(p, dir, 0)) { + ai_try_dir(p, dir+1, 0); + ai_try_dir(p, dir-1, 0); + } else { + ai_try_dir(p, dir-1, 0) && ai_try_dir(p, dir-1, 1+(rand() & 3)); + ai_try_dir(p, dir+1, 0) && ai_try_dir(p, dir+1, 1+(rand() & 3)); + ai_try_dir(p, dir, rand() & 3); + } +} + +byte gameover; + +void flash_colliders() { + byte i; + // flash players that collided + for (i=0; i<56; i++) { + //cv_set_frequency(CV_SOUNDCHANNEL_0, 1000+i*8); + //cv_set_attenuation(CV_SOUNDCHANNEL_0, i/2); + if (players[0].collided) players[0].head_attr ^= 0x80; + if (players[1].collided) players[1].head_attr ^= 0x80; + delay(2); + draw_player(&players[0]); + draw_player(&players[1]); + } + //cv_set_attenuation(CV_SOUNDCHANNEL_0, 28); +} + +void make_move() { + byte i; + for (i=0; i MAX_SPEED) frames_per_move--; + // game over? + if (players[0].score != players[1].score) { + if (players[0].score >= MAX_SCORE) + declare_winner(0); + else if (players[1].score >= MAX_SCORE) + declare_winner(1); + } +} + +void play_game() { + gameover = 0; + init_game(); + players[0].human = 1; + while (!gameover) { + play_round(); + } +} + +void setup_graphics() { + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + set_default_palette(); + cv_set_colors(CV_COLOR_TRANSPARENT, CV_COLOR_BLUE); +} + +void main() { + vdp_setup(); + setup_graphics(); + cv_set_screen_active(true); + cv_set_vint_handler(&vint_handler); + draw_playfield(); + play_game(); +} diff --git a/presets/sms-sms-libcv/simplemusic.c b/presets/sms-sms-libcv/simplemusic.c new file mode 100644 index 00000000..074ae15d --- /dev/null +++ b/presets/sms-sms-libcv/simplemusic.c @@ -0,0 +1,50 @@ + +/* +This demonstrates the cvu_play_music() function. +Command-line tools generate the music file from ABC source files. + +For more information, see: +http://www.colecovision.eu/ColecoVision/development/tutorial2.shtml +*/ + +#include +#include +#include + +//#link "common.c" +//#link "chr_generic.c" +#include "common.h" + +extern const unsigned char CHR_GENERIC[8192]; + +const uint16_t notes[] = { 12846, 12334, 11086, 10062, 10062, 9806, 10062, 10574, 11086, 10062, 11086, 12430, 11042, 12334, 12878, 14158, 14158, 12878, 13390, 13646, 10574, 9806, 10574, 12430, 12846, 12334, 11086, 10062, 10062, 9806, 10062, 10574, 11086, 10062, 11086, 12430, 11054, 12334, 12878, 14158, 14158, 12878, 13390, 13646, 10574, 10062, 10062, 10126, 11054, 12334, 12878, 14158, 13902, 14158, 14670, 14158, 13646, 12878, 13390, 13646, 3918, 12878, 14158, 13902, 12878, 12366, 12878, 12366, 12878, 11086, 10062, 9870, 12334, 11054, 11086, 10062, 10062, 9806, 10062, 10574, 11086, 10062, 11086, 12430, 11054, 12334, 12878, 14158, 14158, 12878, 13390, 13646, 10574, 10062, 10062, 10126, 0xffff }; + +#include +struct cvu_music music; + +void setup_graphics() { + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + set_default_palette(); +} + +// change screen colors to show how long the music +// routine takes to run after screen interrupt +void play(void) +{ + cv_set_colors(CV_COLOR_TRANSPARENT, CV_COLOR_BLUE); + cvu_play_music(&music); + cv_set_colors(CV_COLOR_TRANSPARENT, CV_COLOR_TRANSPARENT); +} + +void main(void) +{ + vdp_setup(); + setup_graphics(); + clrscr(); + putstringxy(1, 0, "Simple Music"); + cv_set_screen_active(true); + cvu_init_music(&music); + music.notes = notes; + cv_set_vint_handler(&play); + for(;;); +} diff --git a/presets/sms-sms-libcv/stars.c b/presets/sms-sms-libcv/stars.c new file mode 100644 index 00000000..8b6106d8 --- /dev/null +++ b/presets/sms-sms-libcv/stars.c @@ -0,0 +1,97 @@ +/* +This is a demo of an animated starfield, ported to +the Sega VDP's mode 4. + +Mode 4 has no hardware scrolling registers, so +scrolling requires rewriting the name/pattern tables. + +There is actually only one star in the pattern table, +just a single pixel. We move it vertically between 16 +different character tiles (8 * 16 = 128 pixels high). +We then draw vertical stripes of 8 repeating consecutive +characters into the image table. + +By randomly offsetting where we begin each stripe, we +create what appears to be a random starfield. + +This demo uses an interrupt handler to increment a +counter 60 times per second. We use this counter to +determine the new position of the star pixel when we animate. +*/ + +#include +#include + +//#link "common.c" +//#link "chr_generic.c" +#include "common.h" + +extern const unsigned char CHR_GENERIC[8192]; + +// the starting character index in the pattern table +#define STAR_BASE_CHAR 0xf0 +// 16 tiles * 8 rows = 128 star positions +#define STAR_COUNT (16*8) + +// a random offset for every vertical column +const char star_yoffsets[32] = { + 31, 11, 25, 10, 21, 1, 9, 6, + 22, 3, 7, 14, 15, 18, 0, 29, + 30, 5, 16, 28, 20, 12, 24, 17, + 13, 8, 26, 19, 23, 27, 2, 4 +}; + +// returns the tile index for every (x,y) position +byte starfield_get_tile_xy(byte x, byte y) { + return ((star_yoffsets[x] + y) & 15) + STAR_BASE_CHAR; +} + +// each mode-4 tile is 32 bytes: 8 rows of 4 plane bytes. +// the star pixel lives in plane 0 of a given row. +word starfield_addr(byte index) { + return PATTERN + STAR_BASE_CHAR*32 + index*4; +} + +// set up starfield image and pattern table +void starfield_setup() { + byte x, y; + // clear star patterns + cvu_vmemset(PATTERN + STAR_BASE_CHAR*32, 0, 16*32); + // write starfield image table + for (x=0; x<32; x++) { + for (y=0; y +#include + +#include "common.h" +//#link "common.c" +//#link "chr_generic.c" + +extern const unsigned char CHR_GENERIC[8192]; + +void setup_graphics() { + // copy the font/tileset into the character pattern table + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + // load the default mode-4 palette + set_default_palette(); + // black backdrop + cv_set_colors(CV_COLOR_BLACK, CV_COLOR_BLACK); +} + +void show_text() { + // clear the name table (tile + attribute bytes) + clrscr(); + // draw message at row 0, column 1 + putstringxy(1, 0, "Greetings Professor Falken"); + // turn on display + cv_set_screen_active(true); +} + +void main() { + vdp_setup(); + setup_graphics(); + show_text(); + while (1); // infinite loop +} diff --git a/presets/sms-sms-libcv/text32.c b/presets/sms-sms-libcv/text32.c new file mode 100644 index 00000000..94e558e9 --- /dev/null +++ b/presets/sms-sms-libcv/text32.c @@ -0,0 +1,47 @@ +/* +Demonstration of mode 4 text with per-character colors. + +In mode 4 the name table stores a tile number and an +attribute byte for every cell. The low bit of the +attribute selects one of the two 16-color palettes. +*/ + +#include +#include + +#include "common.h" +//#link "common.c" +//#link "chr_generic.c" + +extern const unsigned char CHR_GENERIC[8192]; + +void setup_graphics() { + // copy the font/tileset into the character pattern table + cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC)); + // load the default mode-4 palette + set_default_palette(); + cv_set_colors(CV_COLOR_BLACK, CV_COLOR_BLACK); +} + +void show_text() { + byte x, y; + // fill the name table with characters + for (y=0; y