From 932d57a89549d42c6fd6672441fbd191171efec1 Mon Sep 17 00:00:00 2001 From: infvaL <38145742+infval@users.noreply.github.com> Date: Mon, 8 Oct 2018 00:39:15 +0300 Subject: [PATCH] Add emscripten, shortcuts Added: * New palettes. * Ghosting (reduce flickering). * Emscripten. * Const update rate 60. * Drag & drop. * Gamepad support. * Keyboard Shortcuts: reset, palette, window size, ghosting, mute audio. Fixes: * Screen X offset (from MAME). Example: 'Bubble World'. * Revert cycles (there was a problem with the pause in 'Hero Kid'). * Loading a rom after loaded 32K rom. * Save/load savestate (new extension is '.svst'). --- common/controls.c | 2 +- common/gpu.c | 266 ++++-- common/gpu.h | 16 +- common/m6502/tables.h | 54 +- common/memorymap.c | 45 +- common/memorymap.h | 6 +- common/sound.c | 21 +- common/sound.h | 7 +- common/supervision.h | 14 +- common/timer.c | 12 + common/timer.h | 4 + common/watara.c | 151 ++- platform/GP2X/main.c | 2 +- platform/GP2X/menues.c | 6 +- platform/NDS/main.c | 4 +- platform/SDL/main.c | 2 +- platform/SDL2/main.c | 631 +++++++++++-- platform/SDL2/sdl2-config.cmake | 10 + platform/WIN/main.c | 2 +- platform/emscripten/Makefile | 49 + platform/emscripten/potator_shell.html | 872 ++++++++++++++++++ .../{distrib => distrib_old}/mkopk.sh | 0 .../{distrib => distrib_old}/potator.opk | Bin .../potator/default.gcw0.desktop | 0 .../{distrib => distrib_old}/potator/icon.png | Bin .../potator/potator-gcw0.dge | Bin .../potator/readme.txt | 0 platform/opendingux/main_od.c | 2 +- platform/opendingux/menu.c | 4 +- 29 files changed, 1835 insertions(+), 347 deletions(-) create mode 100644 platform/SDL2/sdl2-config.cmake create mode 100644 platform/emscripten/Makefile create mode 100644 platform/emscripten/potator_shell.html rename platform/opendingux/{distrib => distrib_old}/mkopk.sh (100%) rename platform/opendingux/{distrib => distrib_old}/potator.opk (100%) rename platform/opendingux/{distrib => distrib_old}/potator/default.gcw0.desktop (100%) rename platform/opendingux/{distrib => distrib_old}/potator/icon.png (100%) rename platform/opendingux/{distrib => distrib_old}/potator/potator-gcw0.dge (100%) rename platform/opendingux/{distrib => distrib_old}/potator/readme.txt (100%) diff --git a/common/controls.c b/common/controls.c index 4d928d8..fb7124f 100644 --- a/common/controls.c +++ b/common/controls.c @@ -23,7 +23,7 @@ void controls_state_write(uint8 type, uint8 data) return; else controls_state = 0; - + if (type) controls_state |= data; else diff --git a/common/gpu.c b/common/gpu.c index dcf1612..1c0c4f6 100644 --- a/common/gpu.c +++ b/common/gpu.c @@ -8,19 +8,64 @@ #ifdef NDS #include #endif - #ifdef _ODSDL_ #include "../platform/opendingux/shared.h" #endif -static uint16 *supervision_palette; -static uint8 gpu_regs[4]; #ifdef NDS #define RGB555(R,G,B) ((((int)(B))<<10)|(((int)(G))<<5)|(((int)(R)))|(1<<15)) #else #define RGB555(R,G,B) ((((int)(B))<<10)|(((int)(G))<<5)|(((int)(R)))) #endif +const static uint8 palettes[COLOUR_SCHEME_COUNT][12] = { +{ + 252, 252, 252, + 168, 168, 168, + 84, 84, 84, + 0, 0, 0, +}, +{ + 252, 154, 0, + 168, 102, 0, + 84, 51, 0, + 0, 0, 0, +}, +{ + 50, 227, 50, + 34, 151, 34, + 17, 76, 17, + 0, 0, 0, +}, +{ + 0, 154, 252, + 0, 102, 168, + 0, 51, 84, + 0, 0, 0, +}, +{ + 224, 248, 208, + 136, 192, 112, + 52, 104, 86, + 8, 24, 32, +}, +{ + 0x70, 0xb0, 0x78, + 0x48, 0x98, 0x90, + 0x24, 0x58, 0x60, + 0x08, 0x24, 0x30, +}, +}; + +static uint16 *supervision_palette; + +#define SB_MAX (GHOSTING_MAX + 1) +static int ghostCount = 0; +static uint8 *screenBuffers[SB_MAX]; +static uint8 screenBufferStartX[SB_MAX]; + +static void add_ghosting(uint32 scanline, uint16 *backbuffer, uint8 start_x, uint8 end_x); + void gpu_init(void) { supervision_palette = (uint16*)malloc(4 * sizeof(int16)); @@ -28,101 +73,42 @@ void gpu_init(void) void gpu_reset(void) { -#if defined(GP2X) - supervision_palette[3] = gp2x_video_RGB_color16( 0, 0, 0); - supervision_palette[2] = gp2x_video_RGB_color16( 85, 85, 85); - supervision_palette[1] = gp2x_video_RGB_color16(170,170,170); - supervision_palette[0] = gp2x_video_RGB_color16(170,170,170); -#elif defined(NDS) - supervision_palette[3] = RGB555( 0, 0, 0); - supervision_palette[2] = RGB555(10,10,10); - supervision_palette[1] = RGB555(20,20,20); - supervision_palette[0] = RGB555(30,30,30); -#elif defined(_ODSDL_) - supervision_palette[3] = PIX_TO_RGB(actualScreen->format, 0, 0, 0); - supervision_palette[2] = PIX_TO_RGB(actualScreen->format, 85, 85, 85); - supervision_palette[1] = PIX_TO_RGB(actualScreen->format, 170, 170, 170); - supervision_palette[0] = PIX_TO_RGB(actualScreen->format, 240, 240, 240); -#else - supervision_palette[3] = RGB555( 0, 0, 0); - supervision_palette[2] = RGB555(10,10,10); - supervision_palette[1] = RGB555(20,20,20); - supervision_palette[0] = RGB555(30,30,30); -#endif - - memset(gpu_regs, 0, 4); + gpu_set_colour_scheme(COLOUR_SCHEME_DEFAULT); + gpu_set_ghosting(0); } void gpu_set_colour_scheme(int colourScheme) { - float greenf = 1; - float bluef = 1; - float redf = 1; - - switch (colourScheme) { - case COLOUR_SCHEME_DEFAULT: - break; - case COLOUR_SCHEME_AMBER: - greenf = 0.61f; - bluef = 0.00f; - redf = 1.00f; - break; - case COLOUR_SCHEME_GREEN: - greenf = 0.90f; - bluef = 0.20f; - redf = 0.20f; - break; - case COLOUR_SCHEME_BLUE: - greenf = 0.30f; - bluef = 0.75f; - redf = 0.30f; - break; - default: - colourScheme = 0; - break; + float c[12]; + int i; + for (i = 0; i < 12; i++) { + c[i] = palettes[colourScheme][i] / 255.0f; } #if defined(GP2X) - supervision_palette[3] = gp2x_video_RGB_color16( 0*redf, 0*greenf, 0*bluef); - supervision_palette[2] = gp2x_video_RGB_color16( 85*redf, 85*greenf, 85*bluef); - supervision_palette[1] = gp2x_video_RGB_color16(170*redf,170*greenf,170*bluef); - supervision_palette[0] = gp2x_video_RGB_color16(255*redf,255*greenf,255*bluef); -#elif defined(NDS) - supervision_palette[3] = RGB555( 0*redf, 0*greenf, 0*bluef); - supervision_palette[2] = RGB555(10*redf,10*greenf,10*bluef); - supervision_palette[1] = RGB555(20*redf,20*greenf,20*bluef); - supervision_palette[0] = RGB555(30*redf,30*greenf,30*bluef); + supervision_palette[3] = gp2x_video_RGB_color16(255*c[9],255*c[10],255*c[11]); + supervision_palette[2] = gp2x_video_RGB_color16(255*c[6],255*c[ 7],255*c[ 8]); + supervision_palette[1] = gp2x_video_RGB_color16(255*c[3],255*c[ 4],255*c[ 5]); + supervision_palette[0] = gp2x_video_RGB_color16(255*c[0],255*c[ 1],255*c[ 2]); #elif defined(_ODSDL_) - int p11 = (int)85 * redf; int p12 = (int)85 * greenf; int p13 = (int)85 * bluef; - int p21 = (int)170 * redf; int p22 = (int)170 * greenf; int p23 = (int)170 * bluef; - int p31 = (int)255 * redf; int p32 = (int)255 * greenf; int p33 = (int)255 * bluef; - supervision_palette[3] = PIX_TO_RGB(actualScreen->format, 0, 0, 0); - supervision_palette[2] = PIX_TO_RGB(actualScreen->format, p11, p12, p13); - supervision_palette[1] = PIX_TO_RGB(actualScreen->format, p21, p22, p23); - supervision_palette[0] = PIX_TO_RGB(actualScreen->format, p31, p32, p33); + supervision_palette[3] = PIX_TO_RGB(actualScreen->format, (int)(255*c[9]),(int)(255*c[10]),(int)(255*c[11])); + supervision_palette[2] = PIX_TO_RGB(actualScreen->format, (int)(255*c[6]),(int)(255*c[ 7]),(int)(255*c[ 8])); + supervision_palette[1] = PIX_TO_RGB(actualScreen->format, (int)(255*c[3]),(int)(255*c[ 4]),(int)(255*c[ 5])); + supervision_palette[0] = PIX_TO_RGB(actualScreen->format, (int)(255*c[0]),(int)(255*c[ 1]),(int)(255*c[ 2])); #else - supervision_palette[3] = RGB555( 0*redf, 0*greenf, 0*bluef); - supervision_palette[2] = RGB555(10*redf,10*greenf,10*bluef); - supervision_palette[1] = RGB555(20*redf,20*greenf,20*bluef); - supervision_palette[0] = RGB555(30*redf,30*greenf,30*bluef); + supervision_palette[3] = RGB555(31*c[9],31*c[10],31*c[11]); + supervision_palette[2] = RGB555(31*c[6],31*c[ 7],31*c[ 8]); + supervision_palette[1] = RGB555(31*c[3],31*c[ 4],31*c[ 5]); + supervision_palette[0] = RGB555(31*c[0],31*c[ 1],31*c[ 2]); #endif } -void gpu_write(uint32 addr, uint8 data) -{ - gpu_regs[(addr&0x03)] = data; -} - -uint8 gpu_read(uint32 addr) -{ - return gpu_regs[(addr&0x03)]; -} - void gpu_render_scanline(uint32 scanline, uint16 *backbuffer) { - uint8 *vram_line = &(memorymap_getUpperRamPointer())[(gpu_regs[2] >> 2) + (scanline*0x30)]; + uint8 *m_reg = memorymap_getRegisters(); + uint8 *vram_line = memorymap_getUpperRamPointer() + (m_reg[XPOS] / 4 + m_reg[YPOS] * 0x30) + (scanline * 0x30); uint8 x; - for (x =0; x < 160; x += 4) + for (x = 0; x < 160; x += 4) { uint8 b = *(vram_line++); backbuffer[3] = supervision_palette[((b >> 6) & 0x03)]; @@ -135,18 +121,110 @@ void gpu_render_scanline(uint32 scanline, uint16 *backbuffer) void gpu_render_scanline_fast(uint32 scanline, uint16 *backbuffer) { - uint8 *vram_line = &(memorymap_getUpperRamPointer())[scanline]; - uint8 x; - uint32 *buf = (uint32 *)backbuffer; + uint8 *vram_line = memorymap_getUpperRamPointer() + scanline; + uint8 x, j, b; uint8 *m_reg = memorymap_getRegisters(); - int start_x = 3 - (m_reg[XPOS] & 3); - int end_x = (163 < (m_reg[XSIZE] | 3) ? 163 : (m_reg[XSIZE] | 3)); - //if (start_x != 3) printf("start_x = %d\n", start_x); - //if (end_x != 163) printf("end_x = %d\n", end_x); - for (x = start_x; x < end_x; x += 4) { - uint8 b = *(vram_line++); - *(buf++) = (supervision_palette[((b >> 2) & 0x03)] << 16) | (supervision_palette[((b >> 0) & 0x03)]); - *(buf++) = (supervision_palette[((b >> 6) & 0x03)] << 16) | (supervision_palette[((b >> 4) & 0x03)]); + uint8 start_x = m_reg[XPOS] & 3; //3 - (m_reg[XPOS] & 3); + uint8 end_x = (163 < (m_reg[XSIZE] | 3) ? 163 : (m_reg[XSIZE] | 3)) - 3; //(163 < (m_reg[XSIZE] | 3) ? 163 : (m_reg[XSIZE] | 3)); + //if (start_x != 0) printf("start_x = %u\n", start_x); + //if (end_x != 160) printf("end_x = %u\n", end_x); + j = start_x; + + // #1 + if (j & 3) { + b = *vram_line++; + b >>= (j & 3) * 2; + } + for (x = 0; x < end_x; x++, j++) { + if (!(j & 3)) { + b = *(vram_line++); + } + backbuffer[x] = supervision_palette[b & 3]; + b >>= 2; + } + // #2 + /*for (x = 0; x < end_x; x++, j++) { + b = vram_line[j >> 2]; + backbuffer[x] = supervision_palette[(b >> ((j & 3) * 2)) & 3]; + }*/ + + if (ghostCount != 0) { + add_ghosting(scanline, backbuffer, start_x, end_x); } } + +void gpu_set_ghosting(int frameCount) +{ + int i; + if (frameCount < 0) + ghostCount = 0; + else if (frameCount > GHOSTING_MAX) + ghostCount = GHOSTING_MAX; + else + ghostCount = frameCount; + + if (ghostCount != 0) { + if (screenBuffers[0] == NULL) { + for (i = 0; i < SB_MAX; i++) { + screenBuffers[i] = malloc(160 * 160 / 4); + } + } + for (i = 0; i < SB_MAX; i++) { + memset(screenBuffers[i], 0, 160 * 160 / 4); + } + } + else { + for (i = 0; i < SB_MAX; i++) { + free(screenBuffers[i]); + screenBuffers[i] = NULL; + } + } +} + +static void add_ghosting(uint32 scanline, uint16 *backbuffer, uint8 start_x, uint8 end_x) +{ + static int curSB = 0; + static int lineCount = 0; + + uint8 *vram_line = memorymap_getUpperRamPointer() + scanline; + uint8 x, i, j; + + screenBufferStartX[curSB] = start_x; + memset(screenBuffers[curSB] + lineCount * 160 / 4, 0, 160 / 4); + for (j = start_x, x = 0; x < end_x; x++, j++) { + uint8 b = vram_line[j >> 2]; + int pixInd = (x + lineCount * 160) / 4; + uint8 innerInd = (j & 3) * 2; + uint8 c = (b >> innerInd) & 3; + if (c == 0) { + for (i = 0; i < ghostCount; i++) { + uint8 sbInd = (curSB + (SB_MAX - 1) - i) % SB_MAX; + innerInd = ((screenBufferStartX[sbInd] + x) & 3) * 2; + c = (screenBuffers[sbInd][pixInd] >> innerInd) & 3; + if (c != 0) { +#if defined(GP2X) || defined(_ODSDL_) + backbuffer[x] = supervision_palette[3 - 3 * i / ghostCount]; +#else + uint8 r = (supervision_palette[c] >> 0) & 31; + uint8 g = (supervision_palette[c] >> 5) & 31; + uint8 b = (supervision_palette[c] >> 10) & 31; + r = r + (((supervision_palette[0] >> 0) & 31) - r) * i / ghostCount; + g = g + (((supervision_palette[0] >> 5) & 31) - g) * i / ghostCount; + b = b + (((supervision_palette[0] >> 10) & 31) - b) * i / ghostCount; + backbuffer[x] = RGB555(r, g, b); +#endif + break; + } + } + } + else { + screenBuffers[curSB][pixInd] |= c << innerInd; + } + } + + if (lineCount == 159) { + curSB = (curSB + 1) % SB_MAX; + } + lineCount = (lineCount + 1) % 160; +} diff --git a/common/gpu.h b/common/gpu.h index aa852da..fb5067f 100644 --- a/common/gpu.h +++ b/common/gpu.h @@ -3,12 +3,24 @@ #include "supervision.h" +enum +{ + COLOUR_SCHEME_DEFAULT, + COLOUR_SCHEME_AMBER, + COLOUR_SCHEME_GREEN, + COLOUR_SCHEME_BLUE, + COLOUR_SCHEME_BGB, + COLOUR_SCHEME_YOUTUBE, + COLOUR_SCHEME_COUNT +}; + +#define GHOSTING_MAX 8 + void gpu_init(void); void gpu_reset(void); void gpu_set_colour_scheme(int colourScheme); -void gpu_write(uint32 addr, uint8 data); -uint8 gpu_read(uint32 addr); void gpu_render_scanline(uint32 scanline, uint16 *backbuffer); void gpu_render_scanline_fast(uint32 scanline, uint16 *backbuffer); +void gpu_set_ghosting(int frameCount); #endif diff --git a/common/m6502/tables.h b/common/m6502/tables.h index 430a12c..4bd9f66 100644 --- a/common/m6502/tables.h +++ b/common/m6502/tables.h @@ -13,45 +13,25 @@ /** changes to this file. **/ /*************************************************************/ +/* FIXME: need to add cycle data for 65C02 - uso. */ static byte Cycles[256] = { - //7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, - //6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, - //6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, - //6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, - //2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, - //2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5, - //2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, - //2,5,2,5,4,4,4,4,2,4,2,5,4,4,4,4, - //2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, - //2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, - //2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7 - - //https://github.com/mamedev/historic-mess/blob/master/src/emu/cpu/m6502/t6502.c - //https://github.com/mamedev/historic-mess/blob/master/src/emu/cpu/m6502/t65c02.c - //0 1 2 3 4 5 6 7 8 9 a b c d e f - 7,6,2,8,3,3,5,5,3,2,2,2,2,4,6,5, // 0 - 2,5,3,8,3,4,6,5,2,4,2,7,4,4,7,5, // 1 - 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,5, // 2 - 2,5,3,8,4,4,6,5,2,4,2,7,4,4,7,5, // 3 - 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,5, // 4 - 2,5,3,8,4,4,6,5,2,4,3,7,5,4,7,5, // 5 - 6,6,2,8,2,3,5,5,4,2,2,2,5,4,6,5, // 6 - 2,5,3,8,4,4,6,5,2,4,4,7,2,4,7,5, // 7 - 2,6,2,6,3,3,3,5,2,2,2,2,4,4,4,5, // 8 - 2,6,4,6,4,4,4,5,2,5,2,5,4,5,5,5, // 9 - 2,6,2,6,3,3,3,5,2,2,2,2,4,4,4,5, // a - 2,5,3,5,4,4,4,5,2,4,2,5,4,4,4,5, // b - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,5, // c - 2,5,3,8,4,4,6,5,2,4,3,7,5,4,7,5, // d - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,5, // e - 2,5,3,8,4,4,6,5,2,4,4,7,5,4,7,5 // f - //0 1 2 3 4 5 6 7 8 9 a b c d e f + 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, + 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, + 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, + 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, + 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5, + 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, + 2,5,2,5,4,4,4,4,2,4,2,5,4,4,4,4, + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7, + 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, + 2,5,2,8,4,4,6,6,2,4,2,7,5,5,7,7 }; byte ZNTable[256] = diff --git a/common/memorymap.c b/common/memorymap.c index 2d41f86..8bd6d65 100644 --- a/common/memorymap.c +++ b/common/memorymap.c @@ -65,7 +65,6 @@ uint8 memorymap_registers_read(uint32 Addr) case 0x02: case 0x03: break; - //return gpu_read(Addr); case 0x20: return controls_read(); case 0x21: @@ -101,7 +100,6 @@ void memorymap_registers_write(uint32 Addr, uint8 Value) case 0x01: case 0x02: case 0x03: - gpu_write(Addr, Value); break; case 0x23: timer_write(Value); @@ -114,19 +112,19 @@ void memorymap_registers_write(uint32 Addr, uint8 Value) return; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - soundport_w(((Addr & 0x4) >> 2), Addr & 3, Value); + sound_soundport_w(((Addr & 0x4) >> 2), Addr & 3, Value); break; case 0x28: case 0x29: case 0x2a: - svision_noise_w(Addr & 0x07, Value); + sound_noise_w(Addr & 0x07, Value); break; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: - svision_sounddma_w(Addr & 0x07, Value); + sound_sounddma_w(Addr & 0x07, Value); break; } } @@ -180,16 +178,17 @@ byte Rd6502(register word Addr) return 0xff; } -void memorymap_load(uint8 *rom, uint32 size) +void memorymap_load(uint8 **rom, uint32 size) { memorymap_programRomSize = size; - memorymap_programRom = rom; + memorymap_programRom = *rom; if (memorymap_programRomSize == 32768) { uint8 *tmp = (uint8 *)malloc(0x10000); memcpy(tmp + 0x0000, memorymap_programRom, 0x8000); memcpy(tmp + 0x8000, memorymap_programRom, 0x8000); free(memorymap_programRom); + *rom = tmp; memorymap_programRom = tmp; memorymap_programRomSize = 0x10000; } @@ -224,3 +223,35 @@ uint8 *memorymap_getRomPointer(void) { return memorymap_programRom; } + +void memorymap_save_state(FILE *fp) +{ + fwrite(memorymap_regs, 1, 0x2000, fp); + fwrite(memorymap_lowerRam, 1, 0x2000, fp); + fwrite(memorymap_upperRam, 1, 0x2000, fp); + + uint32 offset = 0; + offset = memorymap_lowerRomBank - memorymap_programRom; + fwrite(&offset, 1, sizeof(offset), fp); + offset = memorymap_upperRomBank - memorymap_programRom; + fwrite(&offset, 1, sizeof(offset), fp); + + fwrite(&dma_finished, 1, sizeof(dma_finished), fp); + fwrite(&timer_shot, 1, sizeof(timer_shot), fp); +} + +void memorymap_load_state(FILE *fp) +{ + fread(memorymap_regs, 1, 0x2000, fp); + fread(memorymap_lowerRam, 1, 0x2000, fp); + fread(memorymap_upperRam, 1, 0x2000, fp); + + uint32 offset = 0; + fread(&offset, 1, sizeof(offset), fp); + memorymap_lowerRomBank = memorymap_programRom + offset; + fread(&offset, 1, sizeof(offset), fp); + memorymap_upperRomBank = memorymap_programRom + offset; + + fread(&dma_finished, 1, sizeof(dma_finished), fp); + fread(&timer_shot, 1, sizeof(timer_shot), fp); +} diff --git a/common/memorymap.h b/common/memorymap.h index 3bd9831..d16c203 100644 --- a/common/memorymap.h +++ b/common/memorymap.h @@ -2,6 +2,7 @@ #define __MEMORYMAP_H__ #include "supervision.h" +#include enum { @@ -18,7 +19,10 @@ void memorymap_init(void); void memorymap_reset(void); uint8 memorymap_registers_read(uint32 Addr); void memorymap_registers_write(uint32 Addr, uint8 Value); -void memorymap_load(uint8 *rom, uint32 size); +void memorymap_load(uint8 **rom, uint32 size); + +void memorymap_save_state(FILE *fp); +void memorymap_load_state(FILE *fp); uint8 *memorymap_getUpperRamPointer(void); uint8 *memorymap_getLowerRamPointer(void); diff --git a/common/sound.c b/common/sound.c index 22c90be..0f4a9b5 100644 --- a/common/sound.c +++ b/common/sound.c @@ -40,6 +40,13 @@ typedef struct { } SVISION_DMA; SVISION_DMA m_dma; +void sound_reset(void) +{ + memset(m_channel, 0, sizeof(m_channel)); + memset(&m_noise, 0, sizeof(m_noise) ); + memset(&m_dma, 0, sizeof(m_dma) ); +} + void sound_stream_update(uint8 *stream, int len) { int i, j; @@ -48,14 +55,14 @@ void sound_stream_update(uint8 *stream, int len) uint8 *left = stream + 0; uint8 *right = stream + 1; - for (i = 0; i < len >> 1; i++, left+=2, right+=2) { + for (i = 0; i < len >> 1; i++, left += 2, right += 2) { s = 0; *left = *right = 0; for (channel = m_channel, j = 0; j < 2; j++, channel++) { if (channel->size != 0) { if (channel->on || channel->count) { - int on = FALSE; + BOOL on = FALSE; switch (channel->waveform) { case 0: on = channel->pos <= (28 * channel->size) >> 5; @@ -71,7 +78,7 @@ void sound_stream_update(uint8 *stream, int len) on = channel->pos <= (9 * channel->size) >> 5; break; } - s = on ? channel->volume : 0; // << 8 : 0; + s = on ? channel->volume /*<< 8*/ : 0; if (j == 0) { *right += s; } @@ -87,13 +94,13 @@ void sound_stream_update(uint8 *stream, int len) if (m_noise.on && (m_noise.play || m_noise.count)) { s = (m_noise.value ? 1 /*<< 8*/ : 0) * m_noise.volume; - int b1, b2; if (m_noise.left) *left += s; if (m_noise.right) *right += s; m_noise.pos += m_noise.step; if (m_noise.pos >= 1.0) { + BOOL b1, b2; switch (m_noise.type) { case SVISION_NOISE_Type7Bit: m_noise.value = m_noise.state & 0x40 ? 1 : 0; @@ -152,7 +159,7 @@ void sound_decrement(void) m_noise.count--; } -void soundport_w(int which, int offset, int data) +void sound_soundport_w(int which, int offset, int data) { SVISION_CHANNEL *channel = &m_channel[which]; unsigned short size; @@ -182,7 +189,7 @@ void soundport_w(int which, int offset, int data) } } -void svision_sounddma_w(int offset, int data) +void sound_sounddma_w(int offset, int data) { m_dma.reg[offset] = data; switch (offset) { @@ -208,7 +215,7 @@ void svision_sounddma_w(int offset, int data) } } -void svision_noise_w(int offset, int data) +void sound_noise_w(int offset, int data) { m_noise.reg[offset] = data; switch (offset) { diff --git a/common/sound.h b/common/sound.h index a3d060d..5d7f80f 100644 --- a/common/sound.h +++ b/common/sound.h @@ -5,14 +5,15 @@ #define BPS 44100 +void sound_reset(void); /*! * Generate U8, 2 channels. * \param len in bytes. */ void sound_stream_update(uint8 *stream, int len); void sound_decrement(void); -void soundport_w(int which, int offset, int data); -void svision_sounddma_w(int offset, int data); -void svision_noise_w(int offset, int data); +void sound_soundport_w(int which, int offset, int data); +void sound_sounddma_w(int offset, int data); +void sound_noise_w(int offset, int data); #endif diff --git a/common/supervision.h b/common/supervision.h index a55dba5..e6d9fb8 100644 --- a/common/supervision.h +++ b/common/supervision.h @@ -13,21 +13,17 @@ #include "./m6502/m6502.h" -#define COLOUR_SCHEME_DEFAULT 0 -#define COLOUR_SCHEME_AMBER 1 -#define COLOUR_SCHEME_GREEN 2 -#define COLOUR_SCHEME_BLUE 3 - void supervision_init(void); void supervision_reset(void); void supervision_done(void); void supervision_exec(uint16 *backbuffer); -BOOL supervision_load(uint8 *rom, uint32 romSize); +BOOL supervision_load(uint8 **rom, uint32 romSize); BOOL supervision_update_input(void); -void supervision_set_colour_scheme(int ws_colourScheme); +void supervision_set_colour_scheme(int colourScheme); +void supervision_set_ghosting(int frameCount); M6502 *supervision_get6502regs(void); -int sv_loadState(const char *statepath, int id); -int sv_saveState(const char *statepath, int id); +int supervision_save_state(const char *statepath, int id); +int supervision_load_state(const char *statepath, int id); #endif diff --git a/common/timer.c b/common/timer.c index 0f45808..b35b3f8 100644 --- a/common/timer.c +++ b/common/timer.c @@ -31,3 +31,15 @@ void timer_exec(uint32 cycles) } } } + +void timer_save_state(FILE *fp) +{ + fwrite(&timer_cycles, 1, sizeof(timer_cycles), fp); + fwrite(&timer_activated, 1, sizeof(timer_activated), fp); +} + +void timer_load_state(FILE *fp) +{ + fread(&timer_cycles, 1, sizeof(timer_cycles), fp); + fread(&timer_activated, 1, sizeof(timer_activated), fp); +} diff --git a/common/timer.h b/common/timer.h index 6ede0f8..c0cb30c 100644 --- a/common/timer.h +++ b/common/timer.h @@ -2,9 +2,13 @@ #define __TIMER_H__ #include "supervision.h" +#include void timer_reset(void); void timer_write(uint8 data); void timer_exec(uint32 cycles); +void timer_save_state(FILE *fp); +void timer_load_state(FILE *fp); + #endif diff --git a/common/watara.c b/common/watara.c index 40b3107..aab7e9c 100644 --- a/common/watara.c +++ b/common/watara.c @@ -19,7 +19,6 @@ #endif static M6502 m6502_registers; - static BOOL irq = FALSE; void m6502_set_irq_line(BOOL assertLine) @@ -39,27 +38,19 @@ byte Loop6502(register M6502 *R) void supervision_init(void) { - memorymap_init(); gpu_init(); -} - -BOOL supervision_load(uint8 *rom, uint32 romSize) -{ - memorymap_load(rom, romSize); - supervision_reset(); - - return TRUE; + memorymap_init(); } void supervision_reset(void) { - memorymap_reset(); - gpu_reset(); - timer_reset(); controls_reset(); + gpu_reset(); + memorymap_reset(); + sound_reset(); + timer_reset(); Reset6502(&m6502_registers); - irq = FALSE; } @@ -67,14 +58,12 @@ void supervision_done(void) { } -void supervision_set_colour_scheme(int sv_colourScheme) +BOOL supervision_load(uint8 **rom, uint32 romSize) { - gpu_set_colour_scheme(sv_colourScheme); -} + memorymap_load(rom, romSize); + supervision_reset(); -M6502 *supervision_get6502regs(void) -{ - return &m6502_registers; + return TRUE; } BOOL supervision_update_input(void) @@ -82,23 +71,39 @@ BOOL supervision_update_input(void) return controls_update(); } +void supervision_set_colour_scheme(int colourScheme) +{ + gpu_set_colour_scheme(colourScheme); +} + +void supervision_set_ghosting(int frameCount) +{ + gpu_set_ghosting(frameCount); +} + +M6502 *supervision_get6502regs(void) +{ + return &m6502_registers; +} + void supervision_exec(uint16 *backbuffer) { uint32 supervision_scanline, scan = 0; - uint8 *m_reg = memorymap_getRegisters(); - //if (!((m_reg[BANK] >> 3) & 1)) { printf("ndraw "); } - scan = m_reg[XPOS] / 4 + m_reg[YPOS] * 0x30; - for (supervision_scanline = 0; supervision_scanline < 160; supervision_scanline++) - { - m6502_registers.ICount = 512; + for (supervision_scanline = 0; supervision_scanline < 160; supervision_scanline++) { + m6502_registers.ICount = 512; timer_exec(m6502_registers.ICount); Run6502(&m6502_registers); + } + + //if (!((m_reg[BANK] >> 3) & 1)) { printf("LCD off\n"); } + scan = m_reg[XPOS] / 4 + m_reg[YPOS] * 0x30; + for (supervision_scanline = 0; supervision_scanline < 160; supervision_scanline++) { #ifdef NDS gpu_render_scanline(supervision_scanline, backbuffer); - backbuffer += 160+96; + backbuffer += 160 + 96; #else //gpu_render_scanline(supervision_scanline, backbuffer); gpu_render_scanline_fast(scan, backbuffer); @@ -109,84 +114,70 @@ void supervision_exec(uint16 *backbuffer) scan = 0; // SSSnake } - if (Rd6502(0x2026)&0x01) + if (Rd6502(0x2026) & 0x01) Int6502(supervision_get6502regs(), INT_NMI); sound_decrement(); } -int sv_loadState(const char *statepath, int id) +int supervision_save_state(const char *statepath, int id) { FILE *fp; char newPath[256]; strcpy(newPath, statepath); - sprintf(newPath + strlen(newPath) - 3, ".s%d", id); + sprintf(newPath + strlen(newPath), ".svst"); #ifdef GP2X - gp2x_printf(0,10,220,"newPath = %s",newPath); gp2x_video_RGB_flip(0); #endif -#ifdef NDS - iprintf("\nnewPath = %s",newPath); -#endif - - fp = fopen(newPath, "rb"); - - if (fp) { - fread(&m6502_registers, 1, sizeof(m6502_registers), fp); - fread(memorymap_programRom, 1, sizeof(memorymap_programRom), fp); - fread(memorymap_lowerRam, 1, 0x2000, fp); - fread(memorymap_upperRam, 1, 0x2000, fp); - fread(memorymap_lowerRomBank, 1, sizeof(memorymap_lowerRomBank), fp); - fread(memorymap_upperRomBank, 1, sizeof(memorymap_upperRomBank), fp); - fread(memorymap_regs, 1, 0x2000, fp); - fclose(fp); - } - -#ifdef GP2X - sleep(1); -#endif - - return 1; -} - -int sv_saveState(const char *statepath, int id) -{ - FILE *fp; - char newPath[256]; - - strcpy(newPath, statepath); - sprintf(newPath + strlen(newPath) - 3, ".s%d", id); - -#ifdef GP2X - gp2x_printf(0,10,220,"newPath = %s",newPath); - gp2x_video_RGB_flip(0); -#endif -#ifdef NDS - iprintf("\nnewPath = %s",newPath); -#endif fp = fopen(newPath, "wb"); - if (fp) { - fwrite(&m6502_registers, 1, sizeof(m6502_registers), fp); - fwrite(memorymap_programRom, 1, sizeof(memorymap_programRom), fp); - fwrite(memorymap_lowerRam, 1, 0x2000, fp); - fwrite(memorymap_upperRam, 1, 0x2000, fp); - fwrite(memorymap_lowerRomBank, 1, sizeof(memorymap_lowerRomBank), fp); - fwrite(memorymap_upperRomBank, 1, sizeof(memorymap_upperRomBank), fp); - fwrite(memorymap_regs, 1, 0x2000, fp); + fwrite(&m6502_registers, 1, sizeof(m6502_registers), fp); + fwrite(&irq, 1, sizeof(irq), fp); + + memorymap_save_state(fp); + timer_save_state(fp); + fflush(fp); fclose(fp); #ifdef GP2X sync(); #endif } - #ifdef GP2X sleep(1); #endif - + return 1; +} + +int supervision_load_state(const char *statepath, int id) +{ + FILE *fp; + char newPath[256]; + + strcpy(newPath, statepath); + sprintf(newPath + strlen(newPath), ".svst"); + +#ifdef GP2X + gp2x_video_RGB_flip(0); +#endif + + fp = fopen(newPath, "rb"); + if (fp) { + sound_reset(); + + fread(&m6502_registers, 1, sizeof(m6502_registers), fp); + fread(&irq, 1, sizeof(irq), fp); + + memorymap_load_state(fp); + timer_load_state(fp); + + fclose(fp); + } +#ifdef GP2X + sleep(1); +#endif return 1; } diff --git a/platform/GP2X/main.c b/platform/GP2X/main.c index 5ddf241..1ea186f 100644 --- a/platform/GP2X/main.c +++ b/platform/GP2X/main.c @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) if(romname!=NULL){ loadROM(romname); - supervision_load((uint8*)buffer, (uint32)buffer_size); + supervision_load(&buffer, (uint32)buffer_size); } else { handleFileMenu(); // File menu } diff --git a/platform/GP2X/menues.c b/platform/GP2X/menues.c index d63725d..607a2bf 100644 --- a/platform/GP2X/menues.c +++ b/platform/GP2X/menues.c @@ -269,7 +269,7 @@ void handleFileMenu(void) RESIZE(); loadROM(FileList[curFile + virtualFile].fName); textClear(); - supervision_load((uint8*)buffer, (uint32)buffer_size); + supervision_load(&buffer, (uint32)buffer_size); textClear(); return; } @@ -496,8 +496,8 @@ void handleMainMenu(void) case MMOPTION_RESTART: RESIZE(); supervision_reset(); textClear(); return; case MMOPTION_SELECTOR: handleFileMenu(); return; case MMOPTION_OPTIONS: handleOptionsMenu(); textClear(); return; - case MMOPTION_SAVESTATE: sv_saveState(romname,saveSlot); textClear();return; - case MMOPTION_LOADSTATE: sv_loadState(romname,saveSlot); textClear();return; + case MMOPTION_SAVESTATE: supervision_save_state(romname,saveSlot); textClear();return; + case MMOPTION_LOADSTATE: supervision_load_state(romname,saveSlot); textClear();return; case MMOPTION_EXIT: exitMenu(); break; default: return; } diff --git a/platform/NDS/main.c b/platform/NDS/main.c index baa4592..24ec162 100644 --- a/platform/NDS/main.c +++ b/platform/NDS/main.c @@ -121,7 +121,7 @@ void CheckKeys(void) /*if(keys & KEY_START && keys & KEY_SELECT) { dotextmenu(); loadROM(); - supervision_load((uint8*)buffer, (uint32)buffer_size); + supervision_load(&buffer, (uint32)buffer_size); iprintf("\nLoad Rom Seccessfully\n"); }*/ } @@ -148,7 +148,7 @@ int main() iprintf("\nFailed to init fat"); } - supervision_load((uint8*)buffer, (uint32)buffer_size); + supervision_load(&buffer, (uint32)buffer_size); iprintf("\nLoad Rom Seccessfully\n"); while(1) diff --git a/platform/SDL/main.c b/platform/SDL/main.c index 2c6daea..c843a4a 100644 --- a/platform/SDL/main.c +++ b/platform/SDL/main.c @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) supervision_init(); //Init the emulator if(romname) loadROM(romname); else loadROM("rom.sv"); - supervision_load((uint8*)buffer, (uint32)buffer_size); + supervision_load(&buffer, (uint32)buffer_size); while(1) { diff --git a/platform/SDL2/main.c b/platform/SDL2/main.c index 347cf30..bb718bb 100644 --- a/platform/SDL2/main.c +++ b/platform/SDL2/main.c @@ -6,21 +6,36 @@ #include #include +#include + +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "../../common/supervision.h" #include "../../common/sound.h" -#include - #define OR_DIE(cond) \ if (cond) { \ fprintf(stderr, "[Error] SDL: %s\n", SDL_GetError()); \ exit(1); \ } -SDL_bool paused = SDL_FALSE; +#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) -uint16_t screenBuffer[160 * 160]; +#define SCREEN_W 160 +#define SCREEN_H 160 +typedef enum { + MENUSTATE_NONE, + MENUSTATE_DROP_ROM, + MENUSTATE_EMULATION, + MENUSTATE_PAUSE, + MENUSTATE_SET_KEY +} MenuState; + +SDL_bool done = SDL_FALSE; +uint16_t screenBuffer[SCREEN_W * SCREEN_H]; SDL_Window *sdlScreen; SDL_Renderer *sdlRenderer; SDL_Texture *sdlTexture; @@ -28,97 +43,337 @@ SDL_Texture *sdlTexture; uint8_t *buffer; uint32_t bufferSize = 0; +SDL_GameController *controller = NULL; + SDL_bool IsFullscreen(void); void ToggleFullscreen(void); +uint64_t startCounter = 0; +SDL_bool isRefreshRate60 = SDL_FALSE; +void InitCounter(void); +SDL_bool NeedUpdate(void); +void DrawDropROM(void); + +int nextMenuState = 0; +MenuState menuStates[4]; +void PushMenuState(MenuState state); +void PopMenuState(void); +MenuState GetMenuState(void); + +void Reset(void); + +int currentPalette = 0; +void NextPalette(void); + +int windowScale = 4; +void IncreaseWindowSize(void); +void DecreaseWindowSize(void); + +void SaveState(void); +void LoadState(void); + +int audioVolume = SDL_MIX_MAXVOLUME; +void SetVolume(int volume); +void MuteAudio(void); + +int currentGhosting = 0; +void IncreaseGhosting(void); +void DecreaseGhosting(void); + +char *keysNames[] = { + "Right", + "Left", + "Down", + "Up", + "B", + "A", + "Select", + "Start", + + "Toggle Fullscreen", + "Reset", + "Save State", + "Load State", + "Next Palette", + "Decrease Window Size", + "Increase Window Size", + "Decrease Ghosting", + "Increase Ghosting", + "Mute Audio", +}; +int keysMapping[] = { + SDL_SCANCODE_RIGHT, + SDL_SCANCODE_LEFT, + SDL_SCANCODE_DOWN, + SDL_SCANCODE_UP, + SDL_SCANCODE_X, // B + SDL_SCANCODE_C, // A + SDL_SCANCODE_Z, // Select + SDL_SCANCODE_SPACE, // Start + + SDL_SCANCODE_RETURN, + SDL_SCANCODE_TAB, + SDL_SCANCODE_1, + SDL_SCANCODE_2, + SDL_SCANCODE_P, + SDL_SCANCODE_MINUS, + SDL_SCANCODE_EQUALS, + SDL_SCANCODE_LEFTBRACKET, + SDL_SCANCODE_RIGHTBRACKET, + SDL_SCANCODE_M, +}; +void (*keysFuncs[])(void) = { + ToggleFullscreen, + Reset, + SaveState, + LoadState, + NextPalette, + DecreaseWindowSize, + IncreaseWindowSize, + DecreaseGhosting, + IncreaseGhosting, + MuteAudio, +}; +int setButton = -1; +void SetKey(int button); + +char romName[64]; +void SetRomName(const char *path) +{ + const char *p = path + strlen(path); + while (p != path) { + if (*p == '\\' || *p == '/') { + p++; + break; + } + p--; + } + strncpy(romName, p, sizeof(romName)); + romName[sizeof(romName) - 1] = '\0'; +} int LoadROM(const char *filename) { - if (buffer != 0) + if (buffer != NULL) { free(buffer); + buffer = NULL; + } - FILE *romfile = fopen(filename, "rb"); + SDL_RWops *romfile = SDL_RWFromFile(filename, "rb"); if (romfile == NULL) { - printf("fopen(): Unable to open file!\n"); + fprintf(stderr, "SDL_RWFromFile(): Unable to open file!\n"); return 1; } - fseek(romfile, 0, SEEK_END); - bufferSize = ftell(romfile); - fseek(romfile, 0, SEEK_SET); - + bufferSize = (uint32_t)SDL_RWsize(romfile); buffer = (uint8_t *)malloc(bufferSize); - - fread(buffer, bufferSize, 1, romfile); - - if (fclose(romfile) == EOF) { - printf("fclose(): Unable to close file!\n"); + SDL_RWread(romfile, buffer, bufferSize, 1); + if (SDL_RWclose(romfile) != 0) { + fprintf(stderr, "SDL_RWclose(): Unable to close file!\n"); return 1; } + SetRomName(filename); return 0; } +//int LoadROM(const char *filename) +//{ +// if (buffer != NULL) { +// free(buffer); +// buffer = NULL; +// } +// +// FILE *romfile = fopen(filename, "rb"); +// if (romfile == NULL) { +// printf("fopen(): Unable to open file!\n"); +// return 1; +// } +// fseek(romfile, 0, SEEK_END); +// bufferSize = ftell(romfile); +// fseek(romfile, 0, SEEK_SET); +// +// buffer = (uint8_t *)malloc(bufferSize); +// +// fread(buffer, bufferSize, 1, romfile); +// +// if (fclose(romfile) == EOF) { +// printf("fclose(): Unable to close file!\n"); +// return 1; +// } +// SetRomName(filename); +// return 0; +//} + +void LoadBuffer(void) +{ + supervision_load(&buffer, bufferSize); + MenuState prevState = GetMenuState(); + PopMenuState(); + PushMenuState(MENUSTATE_EMULATION); + if (prevState == MENUSTATE_PAUSE) { // Focus wasn't gained + PushMenuState(MENUSTATE_PAUSE); + } + supervision_set_colour_scheme(currentPalette); + supervision_set_ghosting(currentGhosting); +} + +void AudioCallback(void *userdata, uint8_t *stream, int len) +{ + // The alternative of SDL_PauseAudio() + //if (GetMenuState() != MENUSTATE_EMULATION) { + // SDL_memset(stream, 0, len); + // return; + //} + + // U8 to F32 + sound_stream_update(stream, len / 4); + float *s = (float*)(stream + len) - 1; + for (int i = len / 4 - 1; i >= 0; i--) { + // 127 - max + *s-- = stream[i] / 127.0f * audioVolume / (float)SDL_MIX_MAXVOLUME; + } + + // U8 or S8 + /*sound_stream_update(stream, len); + for (int i = 0; i < len; i++) { + stream[i] = (uint8_t)(stream[i] * audioVolume / (float)SDL_MIX_MAXVOLUME); + }*/ +} + void HandleInput(void) { uint8_t controls_state = 0; const uint8_t *keystate = SDL_GetKeyboardState(NULL); - if (keystate[SDL_SCANCODE_RIGHT]) controls_state |= 0x01; - if (keystate[SDL_SCANCODE_LEFT]) controls_state |= 0x02; - if (keystate[SDL_SCANCODE_DOWN]) controls_state |= 0x04; - if (keystate[SDL_SCANCODE_UP]) controls_state |= 0x08; - if (keystate[SDL_SCANCODE_X]) controls_state |= 0x10; // B - if (keystate[SDL_SCANCODE_C]) controls_state |= 0x20; // A - if (keystate[SDL_SCANCODE_Z]) controls_state |= 0x40; // Select - if (keystate[SDL_SCANCODE_SPACE]) controls_state |= 0x80; // Start + if (keystate[keysMapping[0]]) controls_state |= 0x01; + if (keystate[keysMapping[1]]) controls_state |= 0x02; + if (keystate[keysMapping[2]]) controls_state |= 0x04; + if (keystate[keysMapping[3]]) controls_state |= 0x08; + if (keystate[keysMapping[4]]) controls_state |= 0x10; // B + if (keystate[keysMapping[5]]) controls_state |= 0x20; // A + if (keystate[keysMapping[6]]) controls_state |= 0x40; // Select + if (keystate[keysMapping[7]]) controls_state |= 0x80; // Start + + if (SDL_GameControllerGetAttached(controller)) { + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) controls_state |= 0x01; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) controls_state |= 0x02; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) controls_state |= 0x04; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)) controls_state |= 0x08; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)) controls_state |= 0x10; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)) controls_state |= 0x20; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_BACK)) controls_state |= 0x40; + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)) controls_state |= 0x80; + // 31130/32768 == 0.95 + if (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > 31130) controls_state |= 0x01; + if (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -31130) controls_state |= 0x02; + if (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > 31130) controls_state |= 0x04; + if (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -31130) controls_state |= 0x08; + } controls_state_write(0, controls_state); } -void AudioCallback(void *userdata, uint8_t *stream, int len) -{ - //SDL_memset(stream, 0, len); - sound_stream_update(stream, len/4); - // U8 to F32 - int i; - float *s = (float*)(stream + len) - 1; - for (i = len/4 - 1; i >= 0; i--) { - *s-- = stream[i] / 255.0f; - } -} - -void Render(void) -{ - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent(sdlRenderer); -} - void PollEvents(void) { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { - paused = SDL_TRUE; + done = SDL_TRUE; } else if (event.type == SDL_KEYDOWN) { - switch (event.key.keysym.sym) { - case SDLK_RETURN: - ToggleFullscreen(); - break; - case SDLK_1: - sv_saveState("rom ", 0); - break; - case SDLK_2: - sv_loadState("rom ", 0); + if (GetMenuState() == MENUSTATE_SET_KEY) { + if (event.key.keysym.scancode != SDL_SCANCODE_ESCAPE) + keysMapping[setButton] = event.key.keysym.scancode; + PopMenuState(); + SDL_PauseAudio(0); + continue; + } + for (int i = 0; i < COUNT_OF(keysFuncs); i++) { + if (keysMapping[i + 8] == event.key.keysym.scancode) { + keysFuncs[i](); break; + } } } - else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { - if (!IsFullscreen()) - SDL_SetWindowSize(sdlScreen, (event.window.data1 + 80) / 160 * 160, (event.window.data2 + 80) / 160 * 160); + // SDL_CONTROLLERBUTTONDOWN doesn't work + else if (event.type == SDL_JOYBUTTONDOWN) { + if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) { + SaveState(); + } + else if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) { + LoadState(); + } + } + else if (event.type == SDL_WINDOWEVENT) { + switch (event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + if (!IsFullscreen()) { + SDL_SetWindowSize(sdlScreen, + (event.window.data1 + SCREEN_W / 2) / SCREEN_W * SCREEN_W, + (event.window.data2 + SCREEN_H / 2) / SCREEN_H * SCREEN_H); + } + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + if (GetMenuState() == MENUSTATE_SET_KEY) PopMenuState(); + PushMenuState(MENUSTATE_PAUSE); + SDL_PauseAudio(1); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + if (GetMenuState() == MENUSTATE_PAUSE) PopMenuState(); + SDL_PauseAudio(0); + break; + } + } + else if (event.type == SDL_DROPFILE) { + if (LoadROM(event.drop.file) == 0) { + LoadBuffer(); + } + SDL_free(event.drop.file); + } + else if (event.type == SDL_JOYDEVICEADDED) { + if (SDL_IsGameController(event.jdevice.which)) { + controller = SDL_GameControllerOpen(event.jdevice.which); + if (!controller) { + fprintf(stderr, "Could not open gamecontroller %i: %s\n", event.jdevice.which, SDL_GetError()); + } + } } } } +void Loop(void) +{ + PollEvents(); + + HandleInput(); + + while (NeedUpdate()) { + switch (GetMenuState()) { + case MENUSTATE_EMULATION: + supervision_exec(screenBuffer); + break; + case MENUSTATE_DROP_ROM: + DrawDropROM(); + break; + case MENUSTATE_PAUSE: + case MENUSTATE_SET_KEY: + break; + default: + break; + } + } + + // Draw + SDL_UpdateTexture(sdlTexture, NULL, screenBuffer, SCREEN_W * sizeof(uint16_t)); + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent(sdlRenderer); +#ifdef __EMSCRIPTEN__ + if (done) { + emscripten_cancel_main_loop(); + } +#endif +} + int main(int argc, char *argv[]) { OR_DIE(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0); @@ -126,64 +381,62 @@ int main(int argc, char *argv[]) sdlScreen = SDL_CreateWindow("Potator (SDL2)", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - 160*3, 160*3, + SCREEN_W * windowScale, SCREEN_H * windowScale, SDL_WINDOW_RESIZABLE); OR_DIE(sdlScreen == NULL); - + sdlRenderer = SDL_CreateRenderer(sdlScreen, -1, SDL_RENDERER_PRESENTVSYNC); OR_DIE(sdlRenderer == NULL); - - SDL_RenderSetLogicalSize(sdlRenderer, 160, 160); - + + SDL_RenderSetLogicalSize(sdlRenderer, SCREEN_W, SCREEN_H); + sdlTexture = SDL_CreateTexture(sdlRenderer, - SDL_PIXELFORMAT_RGB555, + SDL_PIXELFORMAT_BGR555, SDL_TEXTUREACCESS_STREAMING, - 160, 160); + SCREEN_W, SCREEN_H); OR_DIE(sdlTexture == NULL); SDL_AudioSpec audio_spec; - SDL_memset(&audio_spec, 0, sizeof(SDL_AudioSpec)); + SDL_zero(audio_spec); audio_spec.freq = BPS; audio_spec.channels = 2; audio_spec.samples = 512; - audio_spec.format = AUDIO_F32; // Problem with U8 + audio_spec.format = AUDIO_F32; // Or AUDIO_S8. Problem with AUDIO_U8 audio_spec.callback = AudioCallback; audio_spec.userdata = NULL; - //SDL_OpenAudio(&audio_spec, NULL); - SDL_AudioDeviceID devid = SDL_OpenAudioDevice(NULL, 0, &audio_spec, NULL, 0); - OR_DIE(devid == 0); + OR_DIE(SDL_OpenAudio(&audio_spec, NULL) == -1); + //SDL_AudioDeviceID devid = SDL_OpenAudioDevice(NULL, 0, &audio_spec, NULL, 0); + //OR_DIE(devid == 0); - if (argc <= 1) { - LoadROM("rom.sv"); - } - else { - LoadROM(argv[1]); + printf("# Controls\n"); + for (int i = 0; i < COUNT_OF(keysNames); i++) { + printf("%20s: %s\n", keysNames[i], SDL_GetScancodeName(keysMapping[i])); } + printf("\n"); supervision_init(); - supervision_load(buffer, bufferSize); - //SDL_PauseAudio(0); - SDL_PauseAudioDevice(devid, 0); - - while (!paused) { - PollEvents(); - - HandleInput(); - - // Emulate - supervision_exec(screenBuffer); - - // Draw - SDL_UpdateTexture(sdlTexture, NULL, screenBuffer, 160 * sizeof(uint16_t)); - - Render(); + PushMenuState(MENUSTATE_DROP_ROM); + if (LoadROM(argc <= 1 ? "rom.sv" : argv[1]) == 0) { + LoadBuffer(); } + SDL_PauseAudio(0); + //SDL_PauseAudioDevice(devid, 0); + + InitCounter(); +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(Loop, 0, 1); +#else + while (!done) { + Loop(); + } +#endif + supervision_done(); - //SDL_CloseAudio(); - SDL_CloseAudioDevice(devid); + SDL_CloseAudio(); + //SDL_CloseAudioDevice(devid); SDL_DestroyTexture(sdlTexture); SDL_DestroyRenderer(sdlRenderer); @@ -193,9 +446,11 @@ int main(int argc, char *argv[]) return 0; } +#define FULLSCREEN_FLAG SDL_WINDOW_FULLSCREEN_DESKTOP + SDL_bool IsFullscreen(void) { - return 0 != (SDL_GetWindowFlags(sdlScreen) & SDL_WINDOW_FULLSCREEN_DESKTOP); + return 0 != (SDL_GetWindowFlags(sdlScreen) & FULLSCREEN_FLAG); } void ToggleFullscreen(void) @@ -203,9 +458,11 @@ void ToggleFullscreen(void) static int mouseX; static int mouseY; static SDL_bool cursorInWindow = SDL_FALSE; - +#ifdef __EMSCRIPTEN__ + return; +#endif if (!IsFullscreen()) { - SDL_SetWindowFullscreen(sdlScreen, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_SetWindowFullscreen(sdlScreen, FULLSCREEN_FLAG); SDL_ShowCursor(SDL_DISABLE); int x, y; @@ -219,7 +476,7 @@ void ToggleFullscreen(void) SDL_SetWindowFullscreen(sdlScreen, 0); SDL_ShowCursor(SDL_ENABLE); - // Don't move cursor + // Don't move cursor. Bug? if (cursorInWindow) { SDL_WarpMouseInWindow(sdlScreen, mouseX, mouseY); } @@ -229,3 +486,187 @@ void ToggleFullscreen(void) cursorInWindow = SDL_FALSE; } } + +void InitCounter(void) +{ + SDL_DisplayMode current; + SDL_GetCurrentDisplayMode(0, ¤t); + isRefreshRate60 = (current.refresh_rate == 60); + startCounter = SDL_GetPerformanceCounter(); +} + +SDL_bool NeedUpdate(void) +{ + static double elapsedCounter = 0.0; + static SDL_bool result = SDL_FALSE; + + if (isRefreshRate60) { + result = !result; + } + else { + // New frame + if (!result) { + uint64_t now = SDL_GetPerformanceCounter(); + elapsedCounter += (double)((now - startCounter) * 1000) / SDL_GetPerformanceFrequency(); + startCounter = now; + } + result = elapsedCounter >= 16.666; + if (result) { + elapsedCounter -= 16.666; + } + } + return result; +} + +void DrawDropROM(void) +{ + static uint8_t fade = 0; + char dropRom[] = { + "## ## ### ## ## ### # #" + "# # # # # # # # # # # # ###" + "# # ## # # ## ## # # # #" + "## # # ### # # # ### # #" + }; + uint8_t f = (fade < 32) ? fade : 63 - fade; + uint16_t color = (f << 0) | (f << 5) | (f << 10); + fade = (fade + 1) % 64; + + int width = 28, height = 4; + int scale = 4, start = (SCREEN_W - width * scale) / 2 + SCREEN_W * (SCREEN_H - height * scale) / 2; + for (int j = 0; j < height * scale; j++) { + for (int i = 0; i < width * scale; i++) { + if (dropRom[i / scale + width * (j / scale)] == '#') + screenBuffer[start + i + SCREEN_W * j] = color; + } + } +} + +void PushMenuState(MenuState state) +{ + if (nextMenuState == 0 || (nextMenuState > 0 && menuStates[nextMenuState - 1] != state)) { + menuStates[nextMenuState] = state; + nextMenuState++; + } +} + +void PopMenuState(void) +{ + if (nextMenuState > 0) + nextMenuState--; +} + +MenuState GetMenuState(void) +{ + if (nextMenuState > 0) + return menuStates[nextMenuState - 1]; + return MENUSTATE_NONE; +} + +// Emscripten +void UploadROM(void *newBuffer, int newBufferSize, const char *fileName) +{ + bufferSize = newBufferSize; + if (buffer != NULL) { + free(buffer); + buffer = NULL; + } + buffer = (uint8_t *)malloc(bufferSize); + memcpy(buffer, newBuffer, bufferSize); + + SetRomName(fileName); + LoadBuffer(); +} + +void Reset(void) +{ + if (GetMenuState() == MENUSTATE_EMULATION) + LoadBuffer(); +} + +void NextPalette(void) +{ + currentPalette = (currentPalette + 1) % COLOUR_SCHEME_COUNT; + supervision_set_colour_scheme(currentPalette); +} + +void IncreaseWindowSize(void) +{ + if (IsFullscreen()) + return; + + SDL_DisplayMode dm; + SDL_GetDesktopDisplayMode(0, &dm); + if (SCREEN_W * (windowScale + 1) <= dm.w && SCREEN_H * (windowScale + 1) <= dm.h) { + windowScale++; + SDL_SetWindowSize(sdlScreen, SCREEN_W * windowScale, SCREEN_H * windowScale); + } +} + +void DecreaseWindowSize(void) +{ + if (IsFullscreen()) + return; + + if (windowScale > 1) { + windowScale--; + SDL_SetWindowSize(sdlScreen, SCREEN_W * windowScale, SCREEN_H * windowScale); + } +} + +void SaveState(void) +{ + if (GetMenuState() == MENUSTATE_EMULATION) + supervision_save_state(romName, 0); +} + +void LoadState(void) +{ + if (GetMenuState() == MENUSTATE_EMULATION) + supervision_load_state(romName, 0); +} + +void SetVolume(int volume) +{ + if (volume < 0) + audioVolume = 0; + else if (volume > SDL_MIX_MAXVOLUME) + audioVolume = SDL_MIX_MAXVOLUME; // 128 + else + audioVolume = volume; +} + +void MuteAudio(void) +{ + static int lastVolume = -1; + if (lastVolume == -1) { + lastVolume = audioVolume; + audioVolume = 0; + } + else { + audioVolume = lastVolume; + lastVolume = -1; + } +} + +void IncreaseGhosting(void) +{ + if (currentGhosting < GHOSTING_MAX) { + currentGhosting++; + supervision_set_ghosting(currentGhosting); + } +} + +void DecreaseGhosting(void) +{ + if (currentGhosting > 0) { + currentGhosting--; + supervision_set_ghosting(currentGhosting); + } +} + +void SetKey(int button) +{ + setButton = button; + PushMenuState(MENUSTATE_SET_KEY); + SDL_PauseAudio(1); +} diff --git a/platform/SDL2/sdl2-config.cmake b/platform/SDL2/sdl2-config.cmake new file mode 100644 index 0000000..a1c1d7a --- /dev/null +++ b/platform/SDL2/sdl2-config.cmake @@ -0,0 +1,10 @@ +set(SDL2_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include") + +# Support both 32 and 64 bit builds +if (${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(SDL2_LIBRARY "${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2main.lib") +else () + set(SDL2_LIBRARY "${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2main.lib") +endif () + +string(STRIP "${SDL2_LIBRARY}" SDL2_LIBRARY) diff --git a/platform/WIN/main.c b/platform/WIN/main.c index e12d228..cf8987f 100644 --- a/platform/WIN/main.c +++ b/platform/WIN/main.c @@ -260,7 +260,7 @@ LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) } loadROM(filename); - supervision_load((UINT8*)buffer, (UINT32)buffer_size); + supervision_load(&buffer, (UINT32)buffer_size); execute=TRUE; } break; diff --git a/platform/emscripten/Makefile b/platform/emscripten/Makefile new file mode 100644 index 0000000..6e52be3 --- /dev/null +++ b/platform/emscripten/Makefile @@ -0,0 +1,49 @@ +# Emscripten makefile +# Based on https://github.com/aardappel/lobster/blob/master/dev/emscripten/Makefile + +CC = emcc + +# use -g4 for maximum debug info. +OPTLEVEL = -g4 -O0 +CFLAGS = $(OPTLEVEL) +CFLAGS += -Wall -s USE_SDL=2 + +CSRCS = \ + ../SDL2/main.c \ + ../../common/m6502/m6502.c \ + $(wildcard ../../common/*.c) + +COBJS := $(patsubst %.c,%.o,$(CSRCS)) + +EXPORTED_FUNCTIONS = \ + '_main', \ + '_UploadROM', \ + '_SaveState', \ + '_LoadState', \ + '_NextPalette', \ + '_IncreaseWindowSize', \ + '_DecreaseWindowSize', \ + '_SetVolume', \ + '_SetKey', \ + '_MuteAudio', \ + '_supervision_set_ghosting' + +.PHONY: potator clean clean2 release all default + +# add -s ASSERTIONS=2 when troubleshooting. +#EMCC_WASM_BACKEND=1 +potator: $(COBJS) + $(CC) $(CFLAGS) $(COBJS) \ + -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" \ + -s "EXPORTED_FUNCTIONS=[$(EXPORTED_FUNCTIONS)]" \ + -o index.html --shell-file potator_shell.html + +clean clean2: + -$(RM) $(COBJS) + +release: OPTLEVEL = -O2 +release: clean potator clean2 + +all: potator + +default: all diff --git a/platform/emscripten/potator_shell.html b/platform/emscripten/potator_shell.html new file mode 100644 index 0000000..65bb945 --- /dev/null +++ b/platform/emscripten/potator_shell.html @@ -0,0 +1,872 @@ + + + + + Emscripten-Generated Code + + + +
+

Potator - Watara Supervision Emulator

+
+
+
+ +
+
+
+ + Load ROM +
+ + Save state 1 +
+ + Load state 2 +
+ + Ghosting (reduce flickering) +
+
+
+ + + + +
+ + Next palette P +
+ + Decrease window size -_ +
+ + Increase window size =+ +
+ + Fullscreen +
+
+ +

Controls

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionKeyboardGamepad
RightArrow Right, Axis LeftX+
LeftArrow Left, Axis LeftX-
DownArrow Down, Axis LeftY+
UpArrow Up, Axis LeftY-
BKey XA /
AKey CX /
SelectKey ZBack /
StartSpaceStart /
ResetTab
Save stateDigit 1Left bumper / L1
Load stateDigit 2Right bumper/ R1
Next paletteKey P
Window size -Minus
Window size +Equal
Ghosting -Bracket Left
Ghosting +Bracket Right
MuteKey M
+ +

Savestates !The savestates exist in-memory. They are lost when the page is reloaded.

+
+ +
+ + +
+ +
+
+
+ +

Information

+ Source code: GitHub. +
+
Downloading...
+
+ + + + +
+ + + + +
+
+ {{{ SCRIPT }}} + + diff --git a/platform/opendingux/distrib/mkopk.sh b/platform/opendingux/distrib_old/mkopk.sh similarity index 100% rename from platform/opendingux/distrib/mkopk.sh rename to platform/opendingux/distrib_old/mkopk.sh diff --git a/platform/opendingux/distrib/potator.opk b/platform/opendingux/distrib_old/potator.opk similarity index 100% rename from platform/opendingux/distrib/potator.opk rename to platform/opendingux/distrib_old/potator.opk diff --git a/platform/opendingux/distrib/potator/default.gcw0.desktop b/platform/opendingux/distrib_old/potator/default.gcw0.desktop similarity index 100% rename from platform/opendingux/distrib/potator/default.gcw0.desktop rename to platform/opendingux/distrib_old/potator/default.gcw0.desktop diff --git a/platform/opendingux/distrib/potator/icon.png b/platform/opendingux/distrib_old/potator/icon.png similarity index 100% rename from platform/opendingux/distrib/potator/icon.png rename to platform/opendingux/distrib_old/potator/icon.png diff --git a/platform/opendingux/distrib/potator/potator-gcw0.dge b/platform/opendingux/distrib_old/potator/potator-gcw0.dge similarity index 100% rename from platform/opendingux/distrib/potator/potator-gcw0.dge rename to platform/opendingux/distrib_old/potator/potator-gcw0.dge diff --git a/platform/opendingux/distrib/potator/readme.txt b/platform/opendingux/distrib_old/potator/readme.txt similarity index 100% rename from platform/opendingux/distrib/potator/readme.txt rename to platform/opendingux/distrib_old/potator/readme.txt diff --git a/platform/opendingux/main_od.c b/platform/opendingux/main_od.c index 7580560..1056253 100644 --- a/platform/opendingux/main_od.c +++ b/platform/opendingux/main_od.c @@ -167,7 +167,7 @@ unsigned char potatorLoadROM(char* filename) { fread(rom_buffer, 1, rom_size, romfile); fclose(romfile); - supervision_load(rom_buffer, rom_size); + supervision_load(&rom_buffer, rom_size); // Compute game CRC gameCRC = crc32(0, rom_buffer, rom_size); diff --git a/platform/opendingux/menu.c b/platform/opendingux/menu.c index 618ea90..7a30def 100644 --- a/platform/opendingux/menu.c +++ b/platform/opendingux/menu.c @@ -911,7 +911,7 @@ void menuSaveState(void) { strcpy(szFile, gameName); strcpy(strrchr(szFile, '.'), ".sta"); print_string("Saving...", COLOR_OK, COLOR_BG, 8,240-5 -10*3); - sv_saveState(szFile,1); + supervision_save_state(szFile,1); print_string("Save OK",COLOR_OK,COLOR_BG, 8+10*8,240-5 -10*3); screen_flip(); screen_waitkey(); @@ -926,7 +926,7 @@ void menuLoadState(void) { strcpy(szFile, gameName); strcpy(strrchr(szFile, '.'), ".sta"); print_string("Loading...", COLOR_OK, COLOR_BG, 8,240-5 -10*3); - sv_loadState(szFile,1); + supervision_load_state(szFile,1); print_string("Load OK",COLOR_OK,COLOR_BG, 8+10*8,240-5 -10*3); screen_flip(); screen_waitkey();