aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graftest/Makefile23
-rw-r--r--graftest/blob2c.c117
-rw-r--r--graftest/graftest.c537
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;
+}