diff options
-rw-r--r-- | graftest/Makefile | 23 | ||||
-rw-r--r-- | graftest/blob2c.c | 117 | ||||
-rw-r--r-- | graftest/graftest.c | 537 |
3 files changed, 677 insertions, 0 deletions
diff --git a/graftest/Makefile b/graftest/Makefile new file mode 100644 index 0000000..e16ae6d --- /dev/null +++ b/graftest/Makefile @@ -0,0 +1,23 @@ +HOSTCC=gcc +CC=gcc + +CFLAGS=-Wall -O2 +HOSTCFLAGS=-Wall -O2 + +all: rom.c + gcc -O2 -Wall -o graftest graftest.c rom.c `pkg-config sdl2 --cflags --libs` + +rom.c: blob2c jumpmanjr.rom + ./blob2c jumpmanjr.rom > rom.c 2> rom.h + +blob2c: blob2c.c + $(HOSTCC) $(HOSTCFLAGS) -o blob2c blob2c.c + +jumpmanjr.rom: + ln -s ../jumpmanjr.rom . + +test: all + ./graftest + +clean: + rm -f *.o graftest core blob2c jumpmanjr.rom rom.h rom.c diff --git a/graftest/blob2c.c b/graftest/blob2c.c new file mode 100644 index 0000000..779b79f --- /dev/null +++ b/graftest/blob2c.c @@ -0,0 +1,117 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> + +/* since we're emitting C source, the comments containing the + ASCII dump better not contain C comment markers! */ +void fixasc(char *asc, int len) { + int j; + + for(j=0; j<(len-1); j++) { + /* slash-star or slash-slash become slash-dot */ + if(asc[j] == '/' && (asc[j+1] == '*' || asc[j+1] == '/')) + asc[j+1] = '.'; + /* star-slash becomes dot-slash */ + else if(asc[j] == '*' && asc[j+1] == '/') + asc[j] = '.'; + } +} + +int main(int argc, char **argv) { + int i, j, count = 0; + char *p, asc[9]; + FILE *in; + + if(argc != 2) { + fprintf(stderr, + "#error usage: %s blobfile >blobfile.c 2>blobfile.h\n", argv[0]); + exit(1); + } + + if( !(in = fopen(argv[1], "rb")) ) { + fprintf(stderr, "/* %s: %s */\n", argv[1], strerror(errno)); + exit(1); + } + + printf("/* C source created by blob2c from input file %s */\n\n", argv[1]); + fprintf(stderr, + "/* C header created by blob2c from input file %s */\n\n", argv[1]); + + for(p = argv[1]; *p; p++) + if(!isalnum(*p)) *p = '_'; + + fprintf(stderr, + "#ifndef %s_H\n" + "#define %s_H\n\n", + argv[1], argv[1]); + + /* start array definition */ + printf("unsigned char %s[] = {", argv[1]); + + asc[8] = '\0'; + + /* read/process each input byte in loop, until EOF */ + while( (i = getc(in)) != EOF ) { + if(count) putchar(','); + + if(count % 8 == 0) { + if(count) { + /* fix & print ASCII dump */ + fixasc(asc, 8); + printf(" /* %s */", asc); + } + + /* start next line */ + printf("\n\t/* %6d */ ", count); + } + + /* store this byte of ASCII dump */ + asc[count % 8] = isprint(i) ? i : '.'; + + /* print this byte of hex data */ + printf("0x%02x", i); + + count++; + } + + /* fix ASCII dump for last line */ + i = count % 8; + if(!i) i = 8; + fixasc(asc, i); + asc[i] = '\0'; + + /* line it up with the previous lines */ + j = (8 - i) * 5; + for(i=0; i<j; i++) + putchar(' '); + + /* print it */ + printf(" /* %s */", asc); + + /* end of array definition */ + printf("\n}; /* %s */\n\n", argv[1]); + + /* array_len definition */ + printf("int %s_len = %d;\n", argv[1], count); + + /* check for read errors */ + i = 0; + if(ferror(in)) { + fprintf(stderr, "#error %s: %s\n", argv[1], strerror(errno)); + i = 1; + } + + fclose(in); + + /* extern declarations to stderr */ + fprintf(stderr, + "extern unsigned char %s[];\nextern int %s_len;\n", + argv[1], argv[1]); + + fprintf(stderr, "\n#endif /* %s_H */\n", argv[1]); + + return i; +} diff --git a/graftest/graftest.c b/graftest/graftest.c new file mode 100644 index 0000000..64d2565 --- /dev/null +++ b/graftest/graftest.c @@ -0,0 +1,537 @@ +#include "SDL.h" + +/* rom.h and rom.c are generated from jumpmanjr.rom */ +#include "rom.h" + +/* this table taken from the atari++ 1.80 source (and modified), + atari++/gtia.cpp */ +int colortable[256] = { + 0x000000, + 0x363636, + 0x515151, + 0x666666, + 0x787878, + 0x888888, + 0x979797, + 0xa5a5a5, + 0xb2b2b2, + 0xbebebe, + 0xcacaca, + 0xd5d5d5, + 0xe0e0e0, + 0xebebeb, + 0xf5f5f5, + 0xffffff, + 0x6a2b00, + 0x7c4900, + 0x8c5f00, + 0x9b7200, + 0xa88300, + 0xb59221, + 0xc1a043, + 0xcdae5a, + 0xd8ba6e, + 0xe3c67f, + 0xedd28f, + 0xf7dc9d, + 0xffe7ab, + 0xfff1b7, + 0xfffbc3, + 0xffffcf, + 0x7f0000, + 0x8e2900, + 0x9d4700, + 0xaa5e00, + 0xb7711e, + 0xc38241, + 0xcf9159, + 0xdaa06d, + 0xe4ad7e, + 0xefba8e, + 0xf9c69c, + 0xffd1aa, + 0xffdcb6, + 0xffe7c3, + 0xfff1ce, + 0xfffbd9, + 0x830000, + 0x920000, + 0xa12a06, + 0xae4837, + 0xba5f51, + 0xc67266, + 0xd28378, + 0xdd9288, + 0xe7a097, + 0xf2ada5, + 0xfbbab2, + 0xffc6bf, + 0xffd1ca, + 0xffdcd6, + 0xffe7e0, + 0xfff1eb, + 0x79000c, + 0x890038, + 0x980052, + 0xa53567, + 0xb24f79, + 0xbf6589, + 0xca7798, + 0xd687a6, + 0xe196b3, + 0xeba4bf, + 0xf5b1cb, + 0xffbed6, + 0xffc9e1, + 0xffd5eb, + 0xffe0f5, + 0xffeaff, + 0x5e0053, + 0x710068, + 0x82007a, + 0x912a8a, + 0x9f4899, + 0xad5fa6, + 0xb972b3, + 0xc583c0, + 0xd192cb, + 0xdca0d6, + 0xe6ade1, + 0xf1baec, + 0xfbc6f6, + 0xffd1ff, + 0xffdcff, + 0xffe7ff, + 0x2a0073, + 0x480084, + 0x5e0093, + 0x7130a1, + 0x824cae, + 0x9262bb, + 0xa075c7, + 0xad85d2, + 0xba94dd, + 0xc6a2e8, + 0xd1b0f2, + 0xdcbcfc, + 0xe7c8ff, + 0xf1d3ff, + 0xfbdeff, + 0xffe9ff, + 0x000082, + 0x000091, + 0x26219f, + 0x4642ad, + 0x5d5ab9, + 0x706ec5, + 0x817fd1, + 0x908fdc, + 0x9f9de6, + 0xacabf1, + 0xb9b7fb, + 0xc5c3ff, + 0xd0cfff, + 0xdbdaff, + 0xe6e5ff, + 0xf0efff, + 0x000081, + 0x001d91, + 0x00409f, + 0x0058ac, + 0x2e6cb9, + 0x4b7ec5, + 0x618dd1, + 0x739cdc, + 0x84a9e6, + 0x93b6f0, + 0xa1c2fa, + 0xafceff, + 0xbbd9ff, + 0xc7e4ff, + 0xd3eeff, + 0xddf8ff, + 0x001f71, + 0x004182, + 0x005992, + 0x006da0, + 0x007ead, + 0x288eba, + 0x479cc6, + 0x5eaad1, + 0x71b7dc, + 0x82c3e7, + 0x91cef1, + 0x9fdafb, + 0xade4ff, + 0xb9efff, + 0xc5f9ff, + 0xd1ffff, + 0x004150, + 0x005965, + 0x006c77, + 0x007e88, + 0x008e97, + 0x1c9ca5, + 0x3faab2, + 0x58b6be, + 0x6cc2ca, + 0x7dced5, + 0x8dd9e0, + 0x9be4ea, + 0xa9eef4, + 0xb6f8fe, + 0xc2ffff, + 0xceffff, + 0x005200, + 0x006734, + 0x00794f, + 0x008964, + 0x009877, + 0x35a687, + 0x50b396, + 0x65bfa4, + 0x77cbb1, + 0x87d6bd, + 0x96e1c9, + 0xa4ebd5, + 0xb1f5df, + 0xbeffea, + 0xcafff4, + 0xd5fffe, + 0x005800, + 0x006c00, + 0x007e00, + 0x208d33, + 0x429c4e, + 0x5aaa64, + 0x6db676, + 0x7fc286, + 0x8ece95, + 0x9dd9a3, + 0xaae4b1, + 0xb7eebd, + 0xc3f8c9, + 0xcfffd4, + 0xdaffdf, + 0xe4ffea, + 0x005500, + 0x1f6900, + 0x417b00, + 0x598b00, + 0x6d9a1a, + 0x7ea73e, + 0x8eb457, + 0x9cc06b, + 0xaacc7d, + 0xb7d78c, + 0xc3e29b, + 0xceeca9, + 0xd9f6b5, + 0xe4ffc2, + 0xeeffcd, + 0xf8ffd8, + 0x434600, + 0x5b5d00, + 0x6e7000, + 0x7f8100, + 0x8f9100, + 0x9d9f20, + 0xabac42, + 0xb8b959, + 0xc4c56d, + 0xcfd17e, + 0xdadc8e, + 0xe5e69d, + 0xeff0aa, + 0xf9fab7, + 0xffffc3, + 0xffffcf, + 0x6a2b00, + 0x7c4900, + 0x8c5f00, + 0x9b7200, + 0xa88300, + 0xb59221, + 0xc1a043, + 0xcdae5a, + 0xd8ba6e, + 0xe3c67f, + 0xedd28f, + 0xf7dc9d, + 0xffe7ab, + 0xfff1b7, + 0xfffbc3, + 0xffffcf +}; + +/* this table taken from the atari800 source, + atari800-2.0.3/src/colours.c */ +/* +int colortable[256] = { + 0x2d2d2d, 0x3b3b3b, 0x494949, 0x575757, + 0x656565, 0x737373, 0x818181, 0x8f8f8f, + 0x9d9d9d, 0xababab, 0xb9b9b9, 0xc7c7c7, + 0xd5d5d5, 0xe3e3e3, 0xf1f1f1, 0xffffff, + 0x5c2300, 0x6a3100, 0x783f00, 0x864d0a, + 0x945b18, 0xa26926, 0xb07734, 0xbe8542, + 0xcc9350, 0xdaa15e, 0xe8af6c, 0xf6bd7a, + 0xffcb88, 0xffd996, 0xffe7a4, 0xfff5b2, + 0x691409, 0x772217, 0x853025, 0x933e33, + 0xa14c41, 0xaf5a4f, 0xbd685d, 0xcb766b, + 0xd98479, 0xe79287, 0xf5a095, 0xffaea3, + 0xffbcb1, 0xffcabf, 0xffd8cd, 0xffe6db, + 0x6c0a38, 0x7a1846, 0x882654, 0x963462, + 0xa44270, 0xb2507e, 0xc05e8c, 0xce6c9a, + 0xdc7aa8, 0xea88b6, 0xf896c4, 0xffa4d2, + 0xffb2e0, 0xffc0ee, 0xffcefc, 0xffdcff, + 0x640565, 0x721373, 0x802181, 0x8e2f8f, + 0x9c3d9d, 0xaa4bab, 0xb859b9, 0xc667c7, + 0xd475d5, 0xe283e3, 0xf091f1, 0xfe9fff, + 0xffadff, 0xffbbff, 0xffc9ff, 0xffd7ff, + 0x520789, 0x601597, 0x6e23a5, 0x7c31b3, + 0x8a3fc1, 0x984dcf, 0xa65bdd, 0xb469eb, + 0xc277f9, 0xd085ff, 0xde93ff, 0xeca1ff, + 0xfaafff, 0xffbdff, 0xffcbff, 0xffd9ff, + 0x3a109c, 0x481eaa, 0x562cb8, 0x643ac6, + 0x7248d4, 0x8056e2, 0x8e64f0, 0x9c72fe, + 0xaa80ff, 0xb88eff, 0xc69cff, 0xd4aaff, + 0xe2b8ff, 0xf0c6ff, 0xfed4ff, 0xffe2ff, + 0x1f1e9c, 0x2d2caa, 0x3b3ab8, 0x4948c6, + 0x5756d4, 0x6564e2, 0x7372f0, 0x8180fe, + 0x8f8eff, 0x9d9cff, 0xabaaff, 0xb9b8ff, + 0xc7c6ff, 0xd5d4ff, 0xe3e2ff, 0xf1f0ff, + 0x072e89, 0x153c97, 0x234aa5, 0x3158b3, + 0x3f66c1, 0x4d74cf, 0x5b82dd, 0x6990eb, + 0x779ef9, 0x85acff, 0x93baff, 0xa1c8ff, + 0xafd6ff, 0xbde4ff, 0xcbf2ff, 0xd9ffff, + 0x003e65, 0x034c73, 0x115a81, 0x1f688f, + 0x2d769d, 0x3b84ab, 0x4992b9, 0x57a0c7, + 0x65aed5, 0x73bce3, 0x81caf1, 0x8fd8ff, + 0x9de6ff, 0xabf4ff, 0xb9ffff, 0xc7ffff, + 0x004b38, 0x005946, 0x096754, 0x177562, + 0x258370, 0x33917e, 0x419f8c, 0x4fad9a, + 0x5dbba8, 0x6bc9b6, 0x79d7c4, 0x87e5d2, + 0x95f3e0, 0xa3ffee, 0xb1fffc, 0xbfffff, + 0x005209, 0x006017, 0x0c6e25, 0x1a7c33, + 0x288a41, 0x36984f, 0x44a65d, 0x52b46b, + 0x60c279, 0x6ed087, 0x7cde95, 0x8aeca3, + 0x98fab1, 0xa6ffbf, 0xb4ffcd, 0xc2ffdb, + 0x005300, 0x0b6100, 0x196f00, 0x277d0a, + 0x358b18, 0x439926, 0x51a734, 0x5fb542, + 0x6dc350, 0x7bd15e, 0x89df6c, 0x97ed7a, + 0xa5fb88, 0xb3ff96, 0xc1ffa4, 0xcfffb2, + 0x134e00, 0x215c00, 0x2f6a00, 0x3d7800, + 0x4b8600, 0x59940b, 0x67a219, 0x75b027, + 0x83be35, 0x91cc43, 0x9fda51, 0xade85f, + 0xbbf66d, 0xc9ff7b, 0xd7ff89, 0xe5ff97, + 0x2d4300, 0x3b5100, 0x495f00, 0x576d00, + 0x657b00, 0x738901, 0x81970f, 0x8fa51d, + 0x9db32b, 0xabc139, 0xb9cf47, 0xc7dd55, + 0xd5eb63, 0xe3f971, 0xf1ff7f, 0xffff8d, + 0x463300, 0x544100, 0x624f00, 0x705d00, + 0x7e6b00, 0x8c790b, 0x9a8719, 0xa89527, + 0xb6a335, 0xc4b143, 0xd2bf51, 0xe0cd5f, + 0xeedb6d, 0xfce97b, 0xfff789, 0xffff97 +}; +*/ + +/* load address of the ROM image */ +#define ROM_START 0x8000 + +/* address within ROM where the level descriptors starts */ +#define LEVEL_BASE 0xa000 + +/* size of each level descriptor in the ROM */ +#define LEVEL_SIZE 0x40 + +Uint32 texture_pixels[160 * 200]; +Uint8 color_regs[4]; + +Uint8 peek(int addr) { + return jumpmanjr_rom[addr - ROM_START]; +} + +Uint16 dpeek(int addr) { + return (peek(addr) | (peek(addr + 1) << 8)); +} + +Uint8 *romptr(int addr) { + return jumpmanjr_rom + (addr - ROM_START); +} + +int getdelta(Uint8 d) { + return (d < 128) ? (d) : (d - 256); +} + +void clear_pixels(void) { + memset(texture_pixels, 0, sizeof(texture_pixels)); +} + +void draw_shape(int shapeaddr, int xpos, int ypos) { + int w = 0, xoffs = 0, yoffs = 0, c = 0; + Uint8 *p = romptr(shapeaddr); + ypos *= 2; + + fprintf(stderr, "draw_shape(%04x, %d, %d);\n", shapeaddr, xpos, ypos); + + while(1) { + if(*p == 0xff) break; + + w = *p++; + xoffs = *p++; + yoffs = 2 * (*p++); + for(c = 0; c < w; c++) { + Uint8 reg = *p++; + fprintf(stderr, "drawing pixel reg %d at %d, %d\n", reg, xpos + xoffs, ypos + yoffs); + texture_pixels[xpos + xoffs + c + (160 * (ypos + yoffs))] = colortable[color_regs[reg]]; + texture_pixels[xpos + xoffs + c + (160 * (ypos + yoffs + 1))] = colortable[color_regs[reg]]; + } + } +} + +void draw_shapes(int shapeaddr, int dx, int dy, int xpos, int ypos, int copies) { + fprintf(stderr, "draw_shapes(%04x, %d, %d, %d, %d, %d);\n", shapeaddr, dx, dy, xpos, ypos, copies); + while(copies--) { + draw_shape(shapeaddr, xpos, ypos); + xpos += dx; + ypos += dy; + } +} + +void draw_map(int addr) { + Uint8 *p = romptr(addr); + int shapeaddr = 0, dx = 0, dy = 0, xpos = 0, ypos = 0, copies = 0; + + clear_pixels(); + + while(1) { + switch(*p) { + case 0xff: /* end opcode */ + return; + + case 0xfe: /* set shape */ + shapeaddr = p[1] | ( p[2] << 8); + p += 3; + break; + + case 0xfd: /* set delta */ + dx = getdelta(p[1]); + dy = getdelta(p[2]); + p += 3; + break; + + case 0xfc: /* jump */ + p = romptr(p[1] | ( p[2] << 8)); + break; + + default: /* draw shape */ + xpos = p[0]; + ypos = p[1]; + copies = p[2]; + draw_shapes(shapeaddr, dx, dy, xpos, ypos, copies); + p += 3; + } + } + +} + +void render_level(int levelnum) { + int leveldesc = LEVEL_BASE + LEVEL_SIZE * levelnum; + int mapaddr = dpeek(leveldesc + 22); + + color_regs[0] = 0; + color_regs[1] = peek(leveldesc + 47); + color_regs[2] = peek(leveldesc + 48); + color_regs[3] = peek(leveldesc + 49); + + fprintf(stderr, "leveldesc %04x, mapaddr %04x\n", leveldesc, mapaddr); + draw_map(mapaddr); + /* + while(1) { + fprintf(stderr, "%04x\n", *p); + if(*p == 0xff) return; + p++; + } + */ +} + +int main(int argc, char **argv) { + int lev = 0, done = 0, fullscreen = 0; + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + SDL_Event event; + + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError()); + return 3; + } + + if(SDL_CreateWindowAndRenderer(320, 200, 0, &window, &renderer)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError()); + return 3; + } + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, 160, 200); + + SDL_RenderSetLogicalSize(renderer, 320, 200); + + render_level(lev); + while(!done) { + Uint32 start, end, now; + + start = SDL_GetTicks(); + end = start + 167; // NTSC timing + + if(SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) { + break; + } + + if(event.type == SDL_KEYDOWN) { + switch(event.key.keysym.sym) { + case SDLK_SPACE: + lev++; + if(lev == 12) lev = 0; + render_level(lev); + break; + + case SDLK_ESCAPE: + done = 1; + break; + + case SDLK_RETURN: + fullscreen = !fullscreen; + SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + break; + + default: + break; + } + } + } + + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00); + SDL_RenderClear(renderer); + + SDL_UpdateTexture(texture, NULL, texture_pixels, 160 * 4); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + + now = SDL_GetTicks(); + if(now < end) { + SDL_Delay(end - now); + // fprintf(stderr, "frame took %d ms\n", now - start); + } else { + // fprintf(stderr, "!! frame took too long, %d ms\n", now - end); + } + } + + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + + SDL_Quit(); + + return 0; +} |