diff --git a/apu/apu.cpp b/apu/apu.cpp index 59a8e145..9fd3cccf 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -619,6 +619,9 @@ void S9xAPUSaveState (uint8 *block) SNES::set_le32(ptr, SNES::dsp.clock); ptr += sizeof(int32); memcpy (ptr, SNES::cpu.registers, 4); + ptr += sizeof(int32); + + memset (ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE-(ptr-block)); } void S9xAPULoadState (uint8 *block) @@ -722,9 +725,9 @@ void S9xAPULoadBlarggState(uint8 *oldblock) SNES::smp.regs.pc = pc; SNES::smp.regs.sp = sp; - SNES::smp.regs.a = a; + SNES::smp.regs.B.a = a; SNES::smp.regs.x = x; - SNES::smp.regs.y = y; + SNES::smp.regs.B.y = y; // blargg's psw has same layout as byuu's flags SNES::smp.regs.p = psw; diff --git a/apu/bapu/smp/core/oppseudo_misc.cpp b/apu/bapu/smp/core/oppseudo_misc.cpp index d266ef92..53ec1f30 100644 --- a/apu/bapu/smp/core/oppseudo_misc.cpp +++ b/apu/bapu/smp/core/oppseudo_misc.cpp @@ -17,37 +17,37 @@ case 0xff: { case 0x9f: { op_io(4); - regs.a = (regs.a >> 4) | (regs.a << 4); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = (regs.B.a >> 4) | (regs.B.a << 4); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } case 0xdf: { op_io(2); - if(regs.p.c || (regs.a) > 0x99) { - regs.a += 0x60; + if(regs.p.c || (regs.B.a) > 0x99) { + regs.B.a += 0x60; regs.p.c = 1; } - if(regs.p.h || (regs.a & 15) > 0x09) { - regs.a += 0x06; + if(regs.p.h || (regs.B.a & 15) > 0x09) { + regs.B.a += 0x06; } - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } case 0xbe: { op_io(2); - if(!regs.p.c || (regs.a) > 0x99) { - regs.a -= 0x60; + if(!regs.p.c || (regs.B.a) > 0x99) { + regs.B.a -= 0x60; regs.p.c = 0; } - if(!regs.p.h || (regs.a & 15) > 0x09) { - regs.a -= 0x06; + if(!regs.p.h || (regs.B.a & 15) > 0x09) { + regs.B.a -= 0x06; } - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } @@ -230,7 +230,7 @@ case 0xf2: { case 0x2d: { op_io(2); - op_writestack(regs.a); + op_writestack(regs.B.a); break; } @@ -242,7 +242,7 @@ case 0x4d: { case 0x6d: { op_io(2); - op_writestack(regs.y); + op_writestack(regs.B.y); break; } @@ -254,7 +254,7 @@ case 0x0d: { case 0xae: { op_io(2); - regs.a = op_readstack(); + regs.B.a = op_readstack(); break; } @@ -266,7 +266,7 @@ case 0xce: { case 0xee: { op_io(2); - regs.y = op_readstack(); + regs.B.y = op_readstack(); break; } @@ -278,12 +278,12 @@ case 0x8e: { case 0xcf: { op_io(8); - ya = regs.y * regs.a; - regs.a = ya; - regs.y = ya >> 8; + ya = regs.B.y * regs.B.a; + regs.B.a = ya; + regs.B.y = ya >> 8; //result is set based on y (high-byte) only - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); break; } @@ -291,21 +291,21 @@ case 0x9e: { op_io(11); ya = regs.ya; //overflow set if quotient >= 256 - regs.p.v = !!(regs.y >= regs.x); - regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); - if(regs.y < (regs.x << 1)) { + regs.p.v = !!(regs.B.y >= regs.x); + regs.p.h = !!((regs.B.y & 15) >= (regs.x & 15)); + if(regs.B.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) - regs.a = ya / regs.x; - regs.y = ya % regs.x; + regs.B.a = ya / regs.x; + regs.B.y = ya % regs.x; } else { - //otherwise, the quotient won't fit into regs.p.v + regs.a + //otherwise, the quotient won't fit into regs.p.v + regs.B.a //this emulates the odd behavior of the S-SMP in this case - regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); - regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + regs.B.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.B.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } diff --git a/apu/bapu/smp/core/oppseudo_mov.cpp b/apu/bapu/smp/core/oppseudo_mov.cpp index fd44ad29..a2219255 100644 --- a/apu/bapu/smp/core/oppseudo_mov.cpp +++ b/apu/bapu/smp/core/oppseudo_mov.cpp @@ -1,22 +1,22 @@ case 0x7d: { op_io(); - regs.a = regs.x; - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = regs.x; + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } case 0xdd: { op_io(); - regs.a = regs.y; - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = regs.B.y; + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } case 0x5d: { op_io(); - regs.x = regs.a; + regs.x = regs.B.a; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; @@ -24,9 +24,9 @@ case 0x5d: { case 0xfd: { op_io(); - regs.y = regs.a; - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.B.y = regs.B.a; + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); break; } @@ -45,9 +45,9 @@ case 0xbd: { } case 0xe8: { - regs.a = op_readpc(); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readpc(); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); break; } @@ -59,9 +59,9 @@ case 0xcd: { } case 0x8d: { - regs.y = op_readpc(); - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.B.y = op_readpc(); + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); break; } @@ -71,9 +71,9 @@ case 0xe6: { op_io(); break; case 2: - regs.a = op_readdp(regs.x); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readdp(regs.x); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -86,10 +86,10 @@ case 0xbf: { op_io(); break; case 2: - regs.a = op_readdp(regs.x++); + regs.B.a = op_readdp(regs.x++); op_io(); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -102,9 +102,9 @@ case 0xe4: { sp = op_readpc(); break; case 2: - regs.a = op_readdp(sp); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readdp(sp); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -132,9 +132,9 @@ case 0xeb: { sp = op_readpc(); break; case 2: - regs.y = op_readdp(sp); - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.B.y = op_readdp(sp); + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } @@ -148,9 +148,9 @@ case 0xf4: { op_io(); break; case 2: - regs.a = op_readdp(sp + regs.x); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -164,7 +164,7 @@ case 0xf9: { op_io(); break; case 2: - regs.x = op_readdp(sp + regs.y); + regs.x = op_readdp(sp + regs.B.y); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; @@ -180,9 +180,9 @@ case 0xfb: { op_io(); break; case 2: - regs.y = op_readdp(sp + regs.x); - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.B.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } @@ -198,9 +198,9 @@ case 0xe5: { sp |= op_readpc() << 8; break; case 3: - regs.a = op_readaddr(sp); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readaddr(sp); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -230,9 +230,9 @@ case 0xec: { sp |= op_readpc() << 8; break; case 2: - regs.y = op_readaddr(sp); - regs.p.n = !!(regs.y & 0x80); - regs.p.z = (regs.y == 0); + regs.B.y = op_readaddr(sp); + regs.p.n = !!(regs.B.y & 0x80); + regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } @@ -247,9 +247,9 @@ case 0xf5: { op_io(); break; case 2: - regs.a = op_readaddr(sp + regs.x); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -264,9 +264,9 @@ case 0xf6: { op_io(); break; case 2: - regs.a = op_readaddr(sp + regs.y); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readaddr(sp + regs.B.y); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -286,9 +286,9 @@ case 0xe7: { sp |= op_readdp(dp + 1) << 8; break; case 4: - regs.a = op_readaddr(sp); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readaddr(sp); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -308,9 +308,9 @@ case 0xf7: { sp |= op_readdp(dp + 1) << 8; break; case 4: - regs.a = op_readaddr(sp + regs.y); - regs.p.n = !!(regs.a & 0x80); - regs.p.z = (regs.a == 0); + regs.B.a = op_readaddr(sp + regs.B.y); + regs.p.n = !!(regs.B.a & 0x80); + regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } @@ -362,7 +362,7 @@ case 0xc6: { op_readdp(regs.x); break; case 3: - op_writedp(regs.x, regs.a); + op_writedp(regs.x, regs.B.a); opcode_cycle = 0; break; } @@ -374,7 +374,7 @@ case 0xaf: { case 1: op_io(2); case 2: - op_writedp(regs.x++, regs.a); + op_writedp(regs.x++, regs.B.a); opcode_cycle = 0; break; } @@ -390,7 +390,7 @@ case 0xc4: { op_readdp(dp); break; case 3: - op_writedp(dp, regs.a); + op_writedp(dp, regs.B.a); opcode_cycle = 0; break; } @@ -422,7 +422,7 @@ case 0xcb: { op_readdp(dp); break; case 3: - op_writedp(dp, regs.y); + op_writedp(dp, regs.B.y); opcode_cycle = 0; break; } @@ -440,7 +440,7 @@ case 0xd4: { op_readdp(dp); break; case 3: - op_writedp(dp, regs.a); + op_writedp(dp, regs.B.a); opcode_cycle = 0; break; } @@ -452,7 +452,7 @@ case 0xd9: { case 1: dp = op_readpc(); op_io(); - dp += regs.y; + dp += regs.B.y; break; case 2: op_readdp(dp); @@ -476,7 +476,7 @@ case 0xdb: { op_readdp(dp); break; case 3: - op_writedp(dp, regs.y); + op_writedp(dp, regs.B.y); opcode_cycle = 0; break; } @@ -495,7 +495,7 @@ case 0xc5: { op_readaddr(dp); break; case 4: - op_writeaddr(dp, regs.a); + op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } @@ -533,7 +533,7 @@ case 0xcc: { op_readaddr(dp); break; case 4: - op_writeaddr(dp, regs.y); + op_writeaddr(dp, regs.B.y); opcode_cycle = 0; break; } @@ -552,7 +552,7 @@ case 0xd5: { op_readaddr(dp); break; case 3: - op_writeaddr(dp, regs.a); + op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } @@ -565,13 +565,13 @@ case 0xd6: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - dp += regs.y; + dp += regs.B.y; break; case 2: op_readaddr(dp); break; case 3: - op_writeaddr(dp, regs.a); + op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } @@ -595,7 +595,7 @@ case 0xc7: { op_readaddr(dp); break; case 5: - op_writeaddr(dp, regs.a); + op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } @@ -613,13 +613,13 @@ case 0xd7: { case 3: dp |= op_readdp(sp + 1) << 8; op_io(); - dp += regs.y; + dp += regs.B.y; break; case 4: op_readaddr(dp); break; case 5: - op_writeaddr(dp, regs.a); + op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } @@ -632,11 +632,11 @@ case 0xba: { sp = op_readpc(); break; case 2: - regs.a = op_readdp(sp); + regs.B.a = op_readdp(sp); op_io(); break; case 3: - regs.y = op_readdp(sp + 1); + regs.B.y = op_readdp(sp + 1); regs.p.n = !!(regs.ya & 0x8000); regs.p.z = (regs.ya == 0); opcode_cycle = 0; @@ -654,10 +654,10 @@ case 0xda: { op_readdp(dp); break; case 3: - op_writedp(dp, regs.a); + op_writedp(dp, regs.B.a); break; case 4: - op_writedp(dp + 1, regs.y); + op_writedp(dp + 1, regs.B.y); opcode_cycle = 0; break; } diff --git a/apu/bapu/smp/core/oppseudo_pc.cpp b/apu/bapu/smp/core/oppseudo_pc.cpp index 022179d1..5c31d493 100644 --- a/apu/bapu/smp/core/oppseudo_pc.cpp +++ b/apu/bapu/smp/core/oppseudo_pc.cpp @@ -251,7 +251,7 @@ case 0x2e: { sp = op_readdp(dp); rd = op_readpc(); op_io(); - if(regs.a == sp){ break; } + if(regs.B.a == sp){ break; } op_io(2); regs.pc += (int8)rd; break; @@ -263,7 +263,7 @@ case 0xde: { sp = op_readdp(dp + regs.x); rd = op_readpc(); op_io(); - if(regs.a == sp){ break; } + if(regs.B.a == sp){ break; } op_io(2); regs.pc += (int8)rd; break; @@ -283,9 +283,9 @@ case 0x6e: { case 0xfe: { rd = op_readpc(); op_io(); - regs.y--; + regs.B.y--; op_io(); - if(regs.y == 0x00){ break; } + if(regs.B.y == 0x00){ break; } op_io(2); regs.pc += (int8)rd; break; diff --git a/apu/bapu/smp/core/oppseudo_read.cpp b/apu/bapu/smp/core/oppseudo_read.cpp index 2a16a3c8..c93e453d 100644 --- a/apu/bapu/smp/core/oppseudo_read.cpp +++ b/apu/bapu/smp/core/oppseudo_read.cpp @@ -1,18 +1,18 @@ case 0x88: { rd = op_readpc(); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } case 0x28: { rd = op_readpc(); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } case 0x68: { rd = op_readpc(); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -24,88 +24,88 @@ case 0xc8: { case 0xad: { rd = op_readpc(); - regs.y = op_cmp(regs.y, rd); + regs.B.y = op_cmp(regs.B.y, rd); break; } case 0x48: { rd = op_readpc(); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } case 0x08: { rd = op_readpc(); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } case 0xa8: { rd = op_readpc(); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x86: { op_io(); rd = op_readdp(regs.x); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } case 0x26: { op_io(); rd = op_readdp(regs.x); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } case 0x66: { op_io(); rd = op_readdp(regs.x); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x46: { op_io(); rd = op_readdp(regs.x); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } case 0x06: { op_io(); rd = op_readdp(regs.x); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } case 0xa6: { op_io(); rd = op_readdp(regs.x); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x84: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } case 0x24: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } case 0x64: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -119,28 +119,28 @@ case 0x3e: { case 0x7e: { dp = op_readpc(); rd = op_readdp(dp); - regs.y = op_cmp(regs.y, rd); + regs.B.y = op_cmp(regs.B.y, rd); break; } case 0x44: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } case 0x04: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } case 0xa4: { dp = op_readpc(); rd = op_readdp(dp); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -148,7 +148,7 @@ case 0x94: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -156,7 +156,7 @@ case 0x34: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -164,7 +164,7 @@ case 0x74: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -172,7 +172,7 @@ case 0x54: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -180,7 +180,7 @@ case 0x14: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -188,7 +188,7 @@ case 0xb4: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -196,7 +196,7 @@ case 0x85: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -204,7 +204,7 @@ case 0x25: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -212,7 +212,7 @@ case 0x65: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -228,7 +228,7 @@ case 0x5e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.y = op_cmp(regs.y, rd); + regs.B.y = op_cmp(regs.B.y, rd); break; } @@ -236,7 +236,7 @@ case 0x45: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -244,7 +244,7 @@ case 0x05: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -252,7 +252,7 @@ case 0xa5: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -261,7 +261,7 @@ case 0x95: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -269,8 +269,8 @@ case 0x96: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_adc(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -279,7 +279,7 @@ case 0x35: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -287,8 +287,8 @@ case 0x36: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_and(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -297,7 +297,7 @@ case 0x75: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -305,8 +305,8 @@ case 0x76: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_cmp(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -315,7 +315,7 @@ case 0x55: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -323,8 +323,8 @@ case 0x56: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_eor(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -333,7 +333,7 @@ case 0x15: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -341,8 +341,8 @@ case 0x16: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_or(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -351,7 +351,7 @@ case 0xb5: { dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -359,8 +359,8 @@ case 0xb6: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); - rd = op_readaddr(dp + regs.y); - regs.a = op_sbc(regs.a, rd); + rd = op_readaddr(dp + regs.B.y); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -370,7 +370,7 @@ case 0x87: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_adc(regs.a, rd); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -380,7 +380,7 @@ case 0x27: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_and(regs.a, rd); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -390,7 +390,7 @@ case 0x67: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_cmp(regs.a, rd); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -400,7 +400,7 @@ case 0x47: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_eor(regs.a, rd); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -410,7 +410,7 @@ case 0x07: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_or(regs.a, rd); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -420,7 +420,7 @@ case 0xa7: { sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); - regs.a = op_sbc(regs.a, rd); + regs.B.a = op_sbc(regs.B.a, rd); break; } @@ -429,8 +429,8 @@ case 0x97: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_adc(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_adc(regs.B.a, rd); break; } @@ -439,8 +439,8 @@ case 0x37: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_and(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_and(regs.B.a, rd); break; } @@ -449,8 +449,8 @@ case 0x77: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_cmp(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_cmp(regs.B.a, rd); break; } @@ -459,8 +459,8 @@ case 0x57: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_eor(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_eor(regs.B.a, rd); break; } @@ -469,8 +469,8 @@ case 0x17: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_or(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_or(regs.B.a, rd); break; } @@ -479,14 +479,14 @@ case 0xb7: { op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; - rd = op_readaddr(sp + regs.y); - regs.a = op_sbc(regs.a, rd); + rd = op_readaddr(sp + regs.B.y); + regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x99: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_adc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); @@ -495,7 +495,7 @@ case 0x99: { case 0x39: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_and(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); @@ -504,7 +504,7 @@ case 0x39: { case 0x79: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_cmp(wr, rd); (0) ? op_writedp(regs.x, wr) : op_io(); @@ -513,7 +513,7 @@ case 0x79: { case 0x59: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_eor(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); @@ -522,7 +522,7 @@ case 0x59: { case 0x19: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_or(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); @@ -531,7 +531,7 @@ case 0x19: { case 0xb9: { op_io(); - rd = op_readdp(regs.y); + rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_sbc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); diff --git a/apu/bapu/smp/core/oppseudo_rmw.cpp b/apu/bapu/smp/core/oppseudo_rmw.cpp index 9b0dd2fb..0664c70f 100644 --- a/apu/bapu/smp/core/oppseudo_rmw.cpp +++ b/apu/bapu/smp/core/oppseudo_rmw.cpp @@ -1,6 +1,6 @@ case 0xbc: { op_io(); - regs.a = op_inc(regs.a); + regs.B.a = op_inc(regs.B.a); break; } @@ -12,13 +12,13 @@ case 0x3d: { case 0xfc: { op_io(); - regs.y = op_inc(regs.y); + regs.B.y = op_inc(regs.B.y); break; } case 0x9c: { op_io(); - regs.a = op_dec(regs.a); + regs.B.a = op_dec(regs.B.a); break; } @@ -30,31 +30,31 @@ case 0x1d: { case 0xdc: { op_io(); - regs.y = op_dec(regs.y); + regs.B.y = op_dec(regs.B.y); break; } case 0x1c: { op_io(); - regs.a = op_asl(regs.a); + regs.B.a = op_asl(regs.B.a); break; } case 0x5c: { op_io(); - regs.a = op_lsr(regs.a); + regs.B.a = op_lsr(regs.B.a); break; } case 0x3c: { op_io(); - regs.a = op_rol(regs.a); + regs.B.a = op_rol(regs.B.a); break; } case 0x7c: { op_io(); - regs.a = op_ror(regs.a); + regs.B.a = op_ror(regs.B.a); break; } @@ -218,10 +218,10 @@ case 0x0e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.p.n = !!((regs.a - rd) & 0x80); - regs.p.z = ((regs.a - rd) == 0); + regs.p.n = !!((regs.B.a - rd) & 0x80); + regs.p.z = ((regs.B.a - rd) == 0); op_readaddr(dp); - op_writeaddr(dp, rd | regs.a); + op_writeaddr(dp, rd | regs.B.a); break; } @@ -229,10 +229,10 @@ case 0x4e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); - regs.p.n = !!((regs.a - rd) & 0x80); - regs.p.z = ((regs.a - rd) == 0); + regs.p.n = !!((regs.B.a - rd) & 0x80); + regs.p.z = ((regs.B.a - rd) == 0); op_readaddr(dp); - op_writeaddr(dp, rd &~ regs.a); + op_writeaddr(dp, rd &~ regs.B.a); break; } diff --git a/apu/bapu/smp/smp.cpp b/apu/bapu/smp/smp.cpp index 1a20b7ae..d0b08cf8 100644 --- a/apu/bapu/smp/smp.cpp +++ b/apu/bapu/smp/smp.cpp @@ -73,9 +73,9 @@ void SMP::reset() { regs.pc = 0xffc0; regs.sp = 0xef; - regs.a = 0x00; + regs.B.a = 0x00; regs.x = 0x00; - regs.y = 0x00; + regs.B.y = 0x00; regs.p = 0x02; //$00f1 diff --git a/apu/bapu/smp/smp.hpp b/apu/bapu/smp/smp.hpp index c96ebea9..cce64a69 100644 --- a/apu/bapu/smp/smp.hpp +++ b/apu/bapu/smp/smp.hpp @@ -58,9 +58,9 @@ public: union { uint16 ya; #ifndef __BIG_ENDIAN__ - struct { uint8 a, y; }; + struct { uint8 a, y; } B; #else - struct { uint8 y, a; }; + struct { uint8 y, a; } B; #endif }; uint8 x; diff --git a/apu/bapu/smp/smp_state.cpp b/apu/bapu/smp/smp_state.cpp index adefdacb..fc604a95 100644 --- a/apu/bapu/smp/smp_state.cpp +++ b/apu/bapu/smp/smp_state.cpp @@ -38,9 +38,9 @@ void SMP::save_spc (uint8 *block) { out.pc_low = regs.pc & 0xff; out.pc_high = (regs.pc >> 8) & 0xff; - out.a = regs.a; + out.a = regs.B.a; out.x = regs.x; - out.y = regs.y; + out.y = regs.B.y; out.psw = (uint8) ((unsigned) regs.p); out.sp = regs.sp; out.unused_a[0] = out.unused_a[1] = 0; @@ -84,9 +84,9 @@ void SMP::save_state(uint8 **block) { INT32(regs.pc); INT32(regs.sp); - INT32(regs.a); + INT32(regs.B.a); INT32(regs.x); - INT32(regs.y); + INT32(regs.B.y); INT32(regs.p.n); INT32(regs.p.v); @@ -146,9 +146,9 @@ void SMP::load_state(uint8 **block) { INT32(regs.pc); INT32(regs.sp); - INT32(regs.a); + INT32(regs.B.a); INT32(regs.x); - INT32(regs.y); + INT32(regs.B.y); INT32(regs.p.n); INT32(regs.p.v); diff --git a/cpuops.cpp b/cpuops.cpp index 112973f0..f0abf199 100644 --- a/cpuops.cpp +++ b/cpuops.cpp @@ -1754,12 +1754,12 @@ static void OpC8Slow (void) if (CheckIndex()) { - Registers.YL--; + Registers.YL++; SetZN(Registers.YL); } else { - Registers.Y.W--; + Registers.Y.W++; SetZN(Registers.Y.W); } } diff --git a/display.h b/display.h index 4f261765..fd50d23d 100644 --- a/display.h +++ b/display.h @@ -179,6 +179,8 @@ #ifndef _DISPLAY_H_ #define _DISPLAY_H_ +#include "snes9x.h" + enum s9x_getdirtype { DEFAULT_DIR = 0, diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 277ad11e..77296e33 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -8,7 +8,7 @@ snes9x_gtk_CXXFLAGS = -fno-exceptions -fno-rtti endif noinst_LIBRARIES = -INCLUDES = -I../apu/bapu -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" +AM_CPPFLAGS = -I../apu/bapu -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" CLEANFILES = \ src/gtk_snes9x_ui.cpp \ diff --git a/gtk/src/gtk_control.cpp b/gtk/src/gtk_control.cpp index 13d935f1..906a2846 100644 --- a/gtk/src/gtk_control.cpp +++ b/gtk/src/gtk_control.cpp @@ -469,7 +469,7 @@ JoyDevice::~JoyDevice (void) } void -JoyDevice::add_event (int parameter, int state) +JoyDevice::add_event (unsigned int parameter, unsigned int state) { JoyEvent event = { parameter, state }; diff --git a/gtk/src/gtk_control.h b/gtk/src/gtk_control.h index 916ad192..3afaa9e3 100644 --- a/gtk/src/gtk_control.h +++ b/gtk/src/gtk_control.h @@ -87,7 +87,7 @@ class JoyDevice private: void poll_events (void); - void add_event (int parameter, int state); + void add_event (unsigned int parameter, unsigned int state); }; #endif diff --git a/gtk/src/gtk_display.cpp b/gtk/src/gtk_display.cpp index c2897e1b..fdd36e7d 100644 --- a/gtk/src/gtk_display.cpp +++ b/gtk/src/gtk_display.cpp @@ -63,10 +63,26 @@ S9xSetEndianess (int type) double S9xGetAspect (void) { - if (gui_config->aspect_ratio) - return (4.0 / 3.0); - else - return (8.0 / 7.0); + double native_aspect = 256.0 / (gui_config->overscan ? 239.0 : 224.0); + double aspect; + + switch (gui_config->aspect_ratio) + { + case 0: /* Square pixels */ + aspect = native_aspect; + break; + + case 1: /* 4:3 */ + aspect = native_aspect * 7 / 6; + break; + + case 2: + default: /* Correct */ + aspect = native_aspect * 8 / 7; + break; + } + + return aspect; } void @@ -84,17 +100,18 @@ S9xApplyAspect (int &s_width, /* Output: x */ { if (gui_config->maintain_aspect_ratio) { - w = s_height * snes_aspect; + w = s_height * snes_aspect + 0.5; h = s_height; x = (d_width - w) / 2; y = (d_height - s_height) / 2; } else { - x = (d_width - s_width) / 2; - y = (d_height - s_height) / 2; w = s_width; h = s_height; + x = (d_width - w) / 2; + y = (d_height - h) / 2; + } } @@ -104,18 +121,20 @@ S9xApplyAspect (int &s_width, /* Output: x */ { if (screen_aspect > snes_aspect) { - x = (d_width - (int) (d_height * snes_aspect)) / 2; - y = 0; - w = (int) (d_height * snes_aspect); + w = d_height * snes_aspect + 0.5; h = d_height; + x = (d_width - w) / 2; + y = 0; + } else { - x = 0; - y = (d_height - (int) (d_width / snes_aspect)) / 2; w = d_width; - h = (int) (d_width / snes_aspect); + h = d_width / snes_aspect + 0.5; + x = 0; + y = (d_height - h) / 2; + } } @@ -718,6 +737,7 @@ S9xMergeHires (void *buffer, return; } +#if 0 static void S9xBlendHires (void *buffer, int pitch, int &width, int &height) { @@ -751,6 +771,7 @@ S9xBlendHires (void *buffer, int pitch, int &width, int &height) return; } +#endif void filter_2x (void *src, diff --git a/gtk/src/gtk_display_driver.h b/gtk/src/gtk_display_driver.h index 3aa11742..d36fd467 100644 --- a/gtk/src/gtk_display_driver.h +++ b/gtk/src/gtk_display_driver.h @@ -6,6 +6,7 @@ class S9xDisplayDriver { public: + virtual ~S9xDisplayDriver() {} virtual void refresh (int width, int height) = 0; virtual int init (void) = 0; virtual void deinit (void) = 0; diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 153bfc17..34ae173a 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -318,16 +318,22 @@ S9xOpenGLDisplayDriver::update (int width, int height) if (using_shaders) { GLint location; + float inputSize[2]; + float outputSize[2]; + float textureSize[2]; - float inputSize[2] = { width, height }; + inputSize[0] = width; + inputSize[1] = height; location = glGetUniformLocation (program, "rubyInputSize"); glUniform2fv (location, 1, inputSize); - float outputSize[2] = {w , h }; + outputSize[0] = w; + outputSize[1] = h; location = glGetUniformLocation (program, "rubyOutputSize"); glUniform2fv (location, 1, outputSize); - float textureSize[2] = { texture_width, texture_height }; + textureSize[0] = texture_width; + textureSize[1] = texture_height; location = glGetUniformLocation (program, "rubyTextureSize"); glUniform2fv (location, 1, textureSize); } @@ -727,14 +733,10 @@ S9xOpenGLDisplayDriver::refresh (int width, int height) void S9xOpenGLDisplayDriver::resize_window (int width, int height) { - XWindowChanges changes; - - changes.width = width; - changes.height = height; - XConfigureWindow (display, xwindow, CWWidth | CWHeight, &changes); - XSync (display, False); - - gdk_window_show (gdk_window); + g_object_unref (gdk_window); + XDestroyWindow (display, xwindow); + create_window (width, height); + glXMakeCurrent (display, xwindow, glx_context); return; } diff --git a/gtk/src/gtk_display_driver_xv.cpp b/gtk/src/gtk_display_driver_xv.cpp index 1333a705..c512dfc8 100644 --- a/gtk/src/gtk_display_driver_xv.cpp +++ b/gtk/src/gtk_display_driver_xv.cpp @@ -39,14 +39,9 @@ S9xXVDisplayDriver::S9xXVDisplayDriver (Snes9xWindow *window, void S9xXVDisplayDriver::resize_window (int width, int height) { - XWindowChanges changes; - - changes.width = width; - changes.height = height; - XConfigureWindow (display, xwindow, CWWidth | CWHeight, &changes); - XSync (display, False); - - gdk_window_show (gdk_window); + g_object_unref (gdk_window); + XDestroyWindow (display, xwindow); + create_window (width, height); return; } diff --git a/gtk/src/gtk_file.cpp b/gtk/src/gtk_file.cpp index a0df75d8..9c0e0009 100644 --- a/gtk/src/gtk_file.cpp +++ b/gtk/src/gtk_file.cpp @@ -465,8 +465,11 @@ S9xOpenROMDialog (void) filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); directory = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); - strncpy (gui_config->last_directory, directory, PATH_MAX); - g_free (directory); + if (directory) + { + strncpy (gui_config->last_directory, directory, PATH_MAX); + g_free (directory); + } } else diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp index 21e5ea34..7c275932 100644 --- a/gtk/src/gtk_s9xwindow.cpp +++ b/gtk/src/gtk_s9xwindow.cpp @@ -100,10 +100,7 @@ event_toggle_interface (GtkWidget *widget, gpointer data) static gboolean event_show_statusbar (GtkWidget *widget, gpointer data) { - Snes9xWindow *window = (Snes9xWindow *) data; - - window->config->statusbar_visible = !window->config->statusbar_visible; - window->configure_widgets (); + ((Snes9xWindow *) data)->toggle_statusbar (); return TRUE; } @@ -307,7 +304,7 @@ event_fullscreen (GtkWidget *widget, gpointer data) static void event_exact_pixels_1x (GtkWidget *widget, gpointer data) { - ((Snes9xWindow *) data)->resize_viewport (256, 224); + ((Snes9xWindow *) data)->resize_to_multiple (1); return; } @@ -315,7 +312,7 @@ event_exact_pixels_1x (GtkWidget *widget, gpointer data) static void event_exact_pixels_2x (GtkWidget *widget, gpointer data) { - ((Snes9xWindow *) data)->resize_viewport (256 * 2, 224 * 2); + ((Snes9xWindow *) data)->resize_to_multiple (2); return; } @@ -323,7 +320,7 @@ event_exact_pixels_2x (GtkWidget *widget, gpointer data) static void event_exact_pixels_3x (GtkWidget *widget, gpointer data) { - ((Snes9xWindow *) data)->resize_viewport (256 * 3, 224 * 3); + ((Snes9xWindow *) data)->resize_to_multiple (3); return; } @@ -331,7 +328,7 @@ event_exact_pixels_3x (GtkWidget *widget, gpointer data) static void event_exact_pixels_4x (GtkWidget *widget, gpointer data) { - ((Snes9xWindow *) data)->resize_viewport (256 * 4, 224 * 4); + ((Snes9xWindow *) data)->resize_to_multiple (4); return; } @@ -339,47 +336,7 @@ event_exact_pixels_4x (GtkWidget *widget, gpointer data) static void event_exact_pixels_5x (GtkWidget *widget, gpointer data) { - ((Snes9xWindow *) data)->resize_viewport (256 * 5, 224 * 5); - - return; -} - -static void -event_correct_aspect_1x (GtkWidget *widget, gpointer data) -{ - ((Snes9xWindow *) data)->resize_viewport (224 * 4 / 3, 224); - - return; -} - -static void -event_correct_aspect_2x (GtkWidget *widget, gpointer data) -{ - ((Snes9xWindow *) data)->resize_viewport (224 * 4 * 2 / 3, 224 * 2); - - return; -} - -static void -event_correct_aspect_3x (GtkWidget *widget, gpointer data) -{ - ((Snes9xWindow *) data)->resize_viewport (224 * 4 * 3 / 3, 224 * 3); - - return; -} - -static void -event_correct_aspect_4x (GtkWidget *widget, gpointer data) -{ - ((Snes9xWindow *) data)->resize_viewport (224 * 4 * 4 / 3, 224 * 4); - - return; -} - -static void -event_correct_aspect_5x (GtkWidget *widget, gpointer data) -{ - ((Snes9xWindow *) data)->resize_viewport (224 * 4 * 5 / 3, 224 * 5); + ((Snes9xWindow *) data)->resize_to_multiple (5); return; } @@ -626,11 +583,6 @@ Snes9xWindow::Snes9xWindow (Snes9xConfig *config) : { "exact_3x", G_CALLBACK (event_exact_pixels_3x) }, { "exact_4x", G_CALLBACK (event_exact_pixels_4x) }, { "exact_5x", G_CALLBACK (event_exact_pixels_5x) }, - { "correct_1x", G_CALLBACK (event_correct_aspect_1x) }, - { "correct_2x", G_CALLBACK (event_correct_aspect_2x) }, - { "correct_3x", G_CALLBACK (event_correct_aspect_3x) }, - { "correct_4x", G_CALLBACK (event_correct_aspect_4x) }, - { "correct_5x", G_CALLBACK (event_correct_aspect_5x) }, { "open_multicart", G_CALLBACK (event_open_multicart) }, { NULL, NULL } @@ -1776,6 +1728,35 @@ Snes9xWindow::draw_background (int x, int y, int w, int h) return; } +void +Snes9xWindow::toggle_statusbar (void) +{ + GtkWidget *item; + GtkAllocation allocation; + int width = 0; + int height = 0; + + item = get_widget ("menubar"); + gtk_widget_get_allocation (item, &allocation); + height += gtk_widget_get_visible (item) ? allocation.height : 0; + + item = get_widget ("drawingarea"); + gtk_widget_get_allocation (item, &allocation); + height += allocation.height; + width = allocation.width; + + config->statusbar_visible = !config->statusbar_visible; + configure_widgets (); + + item = get_widget ("statusbar"); + gtk_widget_get_allocation (item, &allocation); + height += gtk_widget_get_visible (item) ? allocation.height : 0; + + resize (width, height); + + return; +} + void Snes9xWindow::resize_viewport (int width, int height) { @@ -2044,3 +2025,14 @@ Snes9xWindow::update_accels (void) return; } + +void +Snes9xWindow::resize_to_multiple (int factor) +{ + int h = (config->overscan ? 239 : 224) * factor; + int w = h * S9xGetAspect () + 0.5; + + resize_viewport (w, h); + + return; +} diff --git a/gtk/src/gtk_s9xwindow.h b/gtk/src/gtk_s9xwindow.h index 8ae3bb4b..d5350480 100644 --- a/gtk/src/gtk_s9xwindow.h +++ b/gtk/src/gtk_s9xwindow.h @@ -53,6 +53,7 @@ class Snes9xWindow : public GtkBuilderWindow void show (void); void show_status_message (const char *message); void update_statusbar (void); + void toggle_statusbar (void); void draw_background (int x = -1, int y = -1, int w = -1, int h = -1); void draw_background (cairo_t *cr); void set_menu_item_selected (const char *name); @@ -62,6 +63,7 @@ class Snes9xWindow : public GtkBuilderWindow void reset_screensaver (void); void update_accels (void); void toggle_ui (void); + void resize_to_multiple (int factor); void resize_viewport (int width, int height); void expose (GdkEventExpose *event, cairo_t *cr); diff --git a/gtk/src/gtk_sound_driver.h b/gtk/src/gtk_sound_driver.h index 1c66ccd8..034c7012 100644 --- a/gtk/src/gtk_sound_driver.h +++ b/gtk/src/gtk_sound_driver.h @@ -6,6 +6,7 @@ class S9xSoundDriver { public: + virtual ~S9xSoundDriver () {} virtual void init (void) = 0; virtual void terminate (void) = 0; virtual bool8 open_device (void) = 0; diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui index bff0a613..051c2cd8 100644 --- a/gtk/src/snes9x.ui +++ b/gtk/src/snes9x.ui @@ -102,7 +102,6 @@ True True True - False True @@ -264,7 +263,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -385,7 +383,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -402,7 +399,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -459,7 +455,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -477,7 +472,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True @@ -795,6 +789,9 @@ 4:3 SNES correct aspect + + 8*8:7*7 NTSC + @@ -1038,7 +1035,6 @@ True False - False _File True @@ -1049,7 +1045,6 @@ _Open ROM Image... True False - False True image2 False @@ -1061,7 +1056,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False Open Recent True @@ -1078,7 +1072,6 @@ True False Open a ROM to use with NetPlay - False True image3 False @@ -1089,7 +1082,6 @@ True False - False Open _MultiCart... True @@ -1105,7 +1097,6 @@ True False - False _Load State True @@ -1116,7 +1107,6 @@ True False - False Slot _0 True @@ -1126,7 +1116,6 @@ True False - False Slot _1 True @@ -1136,7 +1125,6 @@ True False - False Slot _2 True @@ -1146,7 +1134,6 @@ True False - False Slot _3 True @@ -1156,7 +1143,6 @@ True False - False Slot _4 True @@ -1166,7 +1152,6 @@ True False - False Slot _5 True @@ -1176,7 +1161,6 @@ True False - False Slot _6 True @@ -1186,7 +1170,6 @@ True False - False Slot _7 True @@ -1196,7 +1179,6 @@ True False - False Slot _8 True @@ -1212,7 +1194,6 @@ True False - False From _File... True @@ -1226,7 +1207,6 @@ True False - False _Save State True @@ -1237,7 +1217,6 @@ True False - False Slot _0 True @@ -1247,7 +1226,6 @@ True False - False Slot _1 True @@ -1257,7 +1235,6 @@ True False - False Slot _2 True @@ -1267,7 +1244,6 @@ True False - False Slot _3 True @@ -1277,7 +1253,6 @@ True False - False Slot _4 True @@ -1287,7 +1262,6 @@ True False - False Slot _5 True @@ -1297,7 +1271,6 @@ True False - False Slot _6 True @@ -1307,7 +1280,6 @@ True False - False Slot _7 True @@ -1317,7 +1289,6 @@ True False - False Slot _8 True @@ -1333,7 +1304,6 @@ True False - False To _File... True @@ -1354,7 +1324,6 @@ Save SPC... True False - False True image4 False @@ -1372,7 +1341,6 @@ Show ROM _Info... True False - False True image5 False @@ -1390,7 +1358,6 @@ _Quit True False - False True image18 False @@ -1405,7 +1372,6 @@ True False - False _Emulation True @@ -1416,7 +1382,6 @@ Run / _Continue True False - False True image6 False @@ -1428,7 +1393,6 @@ _Pause True False - False True image7 False @@ -1448,7 +1412,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True image8 False @@ -1461,7 +1424,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True image19 False @@ -1474,7 +1436,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True image9 False @@ -1487,7 +1448,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True image10 False @@ -1505,7 +1465,6 @@ Sy_nc Clients True False - False True image11 False @@ -1524,7 +1483,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True image12 False @@ -1536,7 +1494,6 @@ Soft _Reset True False - False True image13 False @@ -1551,7 +1508,6 @@ True False - False _View True @@ -1563,7 +1519,6 @@ _Hide Menu True False - False True image14 False @@ -1574,7 +1529,6 @@ True False - False _Status Bar True @@ -1591,7 +1545,6 @@ _Change Size True False - False True image17 False @@ -1599,21 +1552,10 @@ True False - - - True - False - False - False - Exact Pixels - True - - True False - False _1x True @@ -1623,7 +1565,6 @@ True False - False _2x True @@ -1633,7 +1574,6 @@ True False - False _3x True @@ -1643,7 +1583,6 @@ True False - False _4x True @@ -1653,78 +1592,11 @@ True False - False _5x True - - - True - False - - - - - True - False - False - False - Correct Aspect - True - - - - - True - False - False - 1x - True - - - - - - True - False - False - 2x - True - - - - - - True - False - False - 3x - True - - - - - - True - False - False - 4x - True - - - - - - True - False - False - 5x - True - - - @@ -1740,7 +1612,6 @@ _Fullscreen True False - False True image15 False @@ -1755,7 +1626,6 @@ True False - False _Options True @@ -1765,7 +1635,6 @@ True False - False Controller Ports True @@ -1775,7 +1644,6 @@ True False - False SNES Port 1 True @@ -1786,7 +1654,6 @@ True False - False Joypad True @@ -1796,7 +1663,6 @@ True False - False Mouse True joypad1 @@ -1807,7 +1673,6 @@ True False - False Superscope True True @@ -1823,7 +1688,6 @@ True False - False SNES Port 2 True @@ -1834,7 +1698,6 @@ True False - False Joypad True @@ -1844,7 +1707,6 @@ True False - False Mouse True joypad2 @@ -1855,7 +1717,6 @@ True False - False Multitap True joypad2 @@ -1866,7 +1727,6 @@ True False - False Superscope True True @@ -1893,7 +1753,6 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False _Cheats... True @@ -1911,7 +1770,6 @@ _Preferences... True False - False True image16 False @@ -1985,7 +1843,6 @@ True True True - False True @@ -2000,7 +1857,6 @@ True True True - False True @@ -2130,7 +1986,6 @@ True True True - False True @@ -2146,7 +2001,6 @@ True True True - False True @@ -2209,7 +2063,6 @@ True True True - False @@ -2223,7 +2076,6 @@ True True True - False @@ -2283,7 +2135,6 @@ True False Connect to another computer that is running Snes9x NetPlay as a server - False True True @@ -2372,7 +2223,6 @@ True False Host a game on this computer as Player 1, requiring extra throughput to support multitple users - False True True connect_radio @@ -2427,7 +2277,6 @@ True False Reset the game when players join instead of transferring potentially unreliable freeze states - False True @@ -2443,7 +2292,6 @@ True False Send the running game image to players instead of requiring them to have their own copies - False True @@ -2608,7 +2456,6 @@ True True False - False True @@ -2624,7 +2471,6 @@ True True False - False True @@ -2641,7 +2487,6 @@ True True False - False True @@ -2656,7 +2501,6 @@ True True True - False True @@ -2729,7 +2573,6 @@ True False Go to fullscreen mode immediately after opening a ROM - False True True @@ -2745,7 +2588,6 @@ True True False - False True True @@ -2762,7 +2604,6 @@ True False Use SNES extended height. Will probably cause letterboxing - False True True @@ -2784,7 +2625,6 @@ True False Changes the screen resolution when running Snes9x in fullscreen mode - False True True @@ -2863,7 +2703,6 @@ True False Scales the image so no black bars are present - False True True @@ -2874,20 +2713,16 @@ - + True False 12 - - Maintain aspect-ratio: + True - True - False - Scales the image as large as possible without distortion - False - True - True + False + 0 + Aspect ratio: False @@ -2909,17 +2744,33 @@ False - True + False 1 - False + True True 1 + + + Maintain aspect-ratio + True + True + False + Scales the image as large as possible without distortion + True + True + + + False + False + 2 + + True @@ -2932,7 +2783,6 @@ True False Allows scaling and filtering to use multiple processors - False True True @@ -2976,7 +2826,7 @@ False True - 2 + 3 @@ -3018,7 +2868,7 @@ False True - 3 + 4 @@ -3062,7 +2912,7 @@ False False - 4 + 5 @@ -3133,7 +2983,6 @@ True True True - False @@ -3148,7 +2997,6 @@ True True True - False @@ -3163,7 +3011,6 @@ True True True - False @@ -3178,7 +3025,6 @@ True True True - False @@ -3571,7 +3417,6 @@ True True False - False True @@ -3755,7 +3600,6 @@ True True False - False True True @@ -3778,7 +3622,6 @@ True False Sync the image to the vertical retrace to stop tearing - False True True @@ -3795,7 +3638,6 @@ True False Sync the program with the video output after every displayed frame to reduce input latency - False True @@ -3811,7 +3653,6 @@ True False Prevents edge artifacts, but can slow performance - False True @@ -3828,7 +3669,6 @@ False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Can be faster or slower depending on drivers - False True @@ -3902,7 +3742,6 @@ True True False - False 0 True @@ -3935,7 +3774,6 @@ True True True - False @@ -3969,7 +3807,6 @@ True False Forces a swapped byte-ordering for cases where the system's endian is used instead of the video card - False True @@ -4123,7 +3960,6 @@ True False Base emulation speed on the rate sound is output - False True @@ -4139,7 +3975,6 @@ True False Disables output of sound - False True True @@ -4156,7 +3991,6 @@ True False Output two channels, left and right - False True True @@ -4479,7 +4313,6 @@ Block invalid VRAM access True False - False True @@ -4495,7 +4328,6 @@ True False Let left and right or up and down be pressed at the same time - False True @@ -4547,7 +4379,6 @@ True True False - False True @@ -4640,7 +4471,6 @@ True True False - False True @@ -4857,7 +4687,6 @@ True True True - False @@ -4873,7 +4702,6 @@ True True True - False @@ -4891,7 +4719,6 @@ True True True - False @@ -4909,7 +4736,6 @@ True True True - False @@ -4927,7 +4753,6 @@ True True True - False @@ -5213,7 +5038,6 @@ True True True - False True @@ -5270,7 +5094,6 @@ True True True - False True @@ -5294,7 +5117,6 @@ True False Allow using modifier keys as independent keys instead of modifiers - False True True @@ -6357,7 +6179,6 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True diff --git a/libretro/Makefile b/libretro/Makefile index f946bec6..352c35af 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -13,47 +13,93 @@ endif CXX = g++ CC = gcc +TARGET_NAME = snes9x ifeq ($(platform), unix) - TARGET := libretro.so + TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC SHARED := -shared -Wl,--version-script=link.T else ifeq ($(platform), osx) - TARGET := libretro.dylib + TARGET := $(TARGET_NAME)_libretro.dylib + fpic := -fPIC -mmacosx-version-min=10.6 + SHARED := -dynamiclib +else ifeq ($(platform), ios) + TARGET := $(TARGET_NAME)_libretro_ios.dylib fpic := -fPIC SHARED := -dynamiclib + + CC = clang -arch armv7 -isysroot $(IOSSDK) -miphoneos-version-min=5.0 + CXX = clang++ -arch armv7 -isysroot $(IOSSDK) -miphoneos-version-min=5.0 + CXXFLAGS += -DIOS -miphoneos-version-min=5.0 + CXXFLAGS += -DARM +else ifeq ($(platform), qnx) + TARGET := $(TARGET_NAME)_libretro_qnx.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T + CC = qcc -Vgcc_notarmv7le + CC = QCC -Vgcc_notarmv7le_cpp + AR = QCC -Vgcc_ntoarmv7le + CXXFLAGS += -D__BLACKBERRY_QNX__ + CXXFLAGS += -DARM else ifeq ($(platform), ps3) - TARGET := libretro_ps3.a + TARGET := $(TARGET_NAME)_libretro_ps3.a CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe - CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + STATIC_LINKING = 1 else ifeq ($(platform), sncps3) - TARGET := libretro_ps3.a + TARGET := $(TARGET_NAME)_libretro_ps3.a CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe - CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + STATIC_LINKING = 1 else ifeq ($(platform), psl1ght) - TARGET := libretro_psl1ght.a + TARGET := $(TARGET_NAME)_libretro_psl1ght.a CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT) CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT) AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT) - CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + STATIC_LINKING = 1 else ifeq ($(platform), xenon) - TARGET := libretro_xenon360.a + TARGET := $(TARGET_NAME)_libretro_xenon360.a CC = xenon-gcc$(EXE_EXT) CXX = xenon-g++$(EXE_EXT) AR = xenon-ar$(EXE_EXT) - CFLAGS += -D__LIBXENON__ -m32 -D__ppc__ + CXXFLAGS += -D__LIBXENON__ -m32 -D__ppc__ + STATIC_LINKING = 1 else ifeq ($(platform), wii) - TARGET := libretro_wii.a + TARGET := $(TARGET_NAME)_libretro_wii.a CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + CXXFLAGS += -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + STATIC_LINKING = 1 +else ifneq (,$(findstring armv,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + SHARED := -shared -Wl,--no-undefined + fpic := -fPIC + CC = gcc + CXX = g++ +ifneq (,$(findstring cortexa8,$(platform))) + CXXFLAGS += -marm -mcpu=cortex-a8 +else ifneq (,$(findstring cortexa9,$(platform))) + CXXFLAGS += -marm -mcpu=cortex-a9 +endif + CXXFLAGS += -marm +ifneq (,$(findstring neon,$(platform))) + CXXFLAGS += -mfpu=neon + HAVE_NEON = 1 +endif +ifneq (,$(findstring softfloat,$(platform))) + CXXFLAGS += -mfloat-abi=softfp +else ifneq (,$(findstring hardfloat,$(platform))) + CXXFLAGS += -mfloat-abi=hard +endif + CXXFLAGS += -DARM else - TARGET := libretro.dll + TARGET := $(TARGET_NAME)_libretro.dll CC = gcc CXX = g++ SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T @@ -79,15 +125,7 @@ CFLAGS = $(CXXFLAGS) all: $(TARGET) $(TARGET): $(OBJECTS) -ifeq ($(platform), ps3) - $(AR) rcs $@ $(OBJECTS) -else ifeq ($(platform), sncps3) - $(AR) rcs $@ $(OBJECTS) -else ifeq ($(platform), psl1ght) - $(AR) rcs $@ $(OBJECTS) -else ifeq ($(platform), xenon) - $(AR) rcs $@ $(OBJECTS) -else ifeq ($(platform), wii) +ifeq ($(STATIC_LINKING), 1) $(AR) rcs $@ $(OBJECTS) else $(CXX) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) -lm diff --git a/libretro/jni/Android.mk b/libretro/jni/Android.mk new file mode 100644 index 00000000..7ec6d3db --- /dev/null +++ b/libretro/jni/Android.mk @@ -0,0 +1,23 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +ifeq ($(TARGET_ARCH),arm) +LOCAL_CFLAGS += -DANDROID_ARM +LOCAL_ARM_MODE := arm +endif + +ifeq ($(TARGET_ARCH),x86) +LOCAL_CFLAGS += -DANDROID_X86 +endif + +ifeq ($(TARGET_ARCH),mips) +LOCAL_CFLAGS += -DANDROID_MIPS +endif + +LOCAL_MODULE := libretro +LOCAL_SRC_FILES = ../../apu/apu.cpp ../../apu/bapu/dsp/sdsp.cpp ../../apu/bapu/dsp/SPC_DSP.cpp ../../apu/bapu/smp/smp.cpp ../../apu/bapu/smp/smp_state.cpp ../../bsx.cpp ../../c4.cpp ../../c4emu.cpp ../../cheats.cpp ../../cheats2.cpp ../../clip.cpp ../../conffile.cpp ../../controls.cpp ../../cpu.cpp ../../cpuexec.cpp ../../cpuops.cpp ../../crosshairs.cpp ../../dma.cpp ../../dsp.cpp ../../dsp1.cpp ../../dsp2.cpp ../../dsp3.cpp ../../dsp4.cpp ../../fxinst.cpp ../../fxemu.cpp ../../gfx.cpp ../../globals.cpp ../../logger.cpp ../../memmap.cpp ../../movie.cpp ../../obc1.cpp ../../ppu.cpp ../../stream.cpp ../../sa1.cpp ../../sa1cpu.cpp ../../screenshot.cpp ../../sdd1.cpp ../../sdd1emu.cpp ../../seta.cpp ../../seta010.cpp ../../seta011.cpp ../../seta018.cpp ../../snapshot.cpp ../../snes9x.cpp ../../spc7110.cpp ../../srtc.cpp ../../tile.cpp ../libretro.cpp +LOCAL_CXXFLAGS = -DANDROID -DARM -D__LIBRETRO__ -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR +LOCAL_C_INCLUDES = ../../ ../../apu/bapu/ + +include $(BUILD_SHARED_LIBRARY) diff --git a/libretro/jni/Application.mk b/libretro/jni/Application.mk new file mode 100644 index 00000000..8a357c3c --- /dev/null +++ b/libretro/jni/Application.mk @@ -0,0 +1,2 @@ +APP_STL := stlport_static +APP_ABI := all diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index e775390d..294443bb 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -21,6 +21,24 @@ #include #include +#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD) +#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN) +#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN) +#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN) + +#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC) + +#define RETRO_GAME_TYPE_BSX 0x101 +#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102 +#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103 +#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104 + +static retro_log_printf_t log_cb = NULL; static retro_video_refresh_t s9x_video_cb = NULL; static retro_audio_sample_t s9x_audio_cb = NULL; static retro_audio_sample_batch_t s9x_audio_batch_cb = NULL; @@ -58,6 +76,89 @@ static bool rom_loaded = false; void retro_set_environment(retro_environment_t cb) { environ_cb = cb; + + const struct retro_variable variables[] = { + // These variable names and possible values constitute an ABI with ZMZ (ZSNES Libretro player). + // Changing "Show layer 1" is fine, but don't change "layer_1"/etc or the possible values ("Yes|No"). + // Adding more variables and rearranging them is safe. + { "s9x_layer_1", "Show layer 1; Yes|No" }, + { "s9x_layer_2", "Show layer 2; Yes|No" }, + { "s9x_layer_3", "Show layer 3; Yes|No" }, + { "s9x_layer_4", "Show layer 4; Yes|No" }, + { "s9x_layer_5", "Show sprite layer; Yes|No" }, + { "s9x_gfx_clip", "Enable graphic clip windows; Yes|No" }, + { "s9x_gfx_transp", "Enable transparency effects; Yes|No" }, + { "s9x_sndchan_1", "Enable sound channel 1; Yes|No" }, + { "s9x_sndchan_2", "Enable sound channel 2; Yes|No" }, + { "s9x_sndchan_3", "Enable sound channel 3; Yes|No" }, + { "s9x_sndchan_4", "Enable sound channel 4; Yes|No" }, + { "s9x_sndchan_5", "Enable sound channel 5; Yes|No" }, + { "s9x_sndchan_6", "Enable sound channel 6; Yes|No" }, + { "s9x_sndchan_7", "Enable sound channel 7; Yes|No" }, + { "s9x_sndchan_8", "Enable sound channel 8; Yes|No" }, + { NULL, NULL }, + }; + + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)variables); + + static const struct retro_controller_description port_1[] = { + { "SNES Joypad", RETRO_DEVICE_JOYPAD }, + { "SNES Mouse", RETRO_DEVICE_MOUSE }, + { "Multitap", RETRO_DEVICE_JOYPAD_MULTITAP }, + }; + + static const struct retro_controller_description port_2[] = { + { "SNES Joypad", RETRO_DEVICE_JOYPAD }, + { "SNES Mouse", RETRO_DEVICE_MOUSE }, + { "Multitap", RETRO_DEVICE_JOYPAD_MULTITAP }, + { "SuperScope", RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE }, + { "Justifier", RETRO_DEVICE_LIGHTGUN_JUSTIFIER }, + }; + + const struct retro_controller_info ports[] = { + { port_1, 3 }, + { port_2, 5 }, + { 0 }, + }; + + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); +} + +static void update_variables(void) +{ + char key[14]; + struct retro_variable var; + + var.key=key; + + int disabled_channels=0; + strcpy(key, "s9x_sndchan_x"); + for (int i=0;i<8;i++) + { + key[strlen("s9x_sndchan_")]='1'+i; + var.value=NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && var.value[0]=='N') disabled_channels|=1<library_name = "SNES9x"; info->library_version = VERSION; - info->valid_extensions = "smc|sfc|zip|gz|swc|fig|jma"; + info->valid_extensions = "smc|sfc|swc|fig"; info->need_fullpath = false; info->block_extract = false; } @@ -106,11 +207,6 @@ void retro_get_system_av_info(struct retro_system_av_info *info) info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0; } -const char *retro_library_id() -{ - return "SNES9x v" VERSION; -} - unsigned retro_api_version() { return RETRO_API_VERSION; @@ -125,55 +221,84 @@ void retro_reset() static unsigned snes_devices[2]; void retro_set_controller_port_device(unsigned port, unsigned device) { - switch (device) + if(port < 2) { - case RETRO_DEVICE_JOYPAD: - S9xSetController(port, CTL_JOYPAD, 0, 0, 0, 0); - snes_devices[port] = RETRO_DEVICE_JOYPAD; - break; - case RETRO_DEVICE_JOYPAD_MULTITAP: - S9xSetController(port, CTL_MP5, 1, 2, 3, 4); - snes_devices[port] = RETRO_DEVICE_JOYPAD_MULTITAP; - break; - case RETRO_DEVICE_MOUSE: - S9xSetController(port, CTL_MOUSE, 0, 0, 0, 0); - snes_devices[port] = RETRO_DEVICE_MOUSE; - break; - case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: - S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); - snes_devices[port] = RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE; - break; - case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: - S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); - snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIER; - break; - case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS: - S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0); - snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIERS; - break; - default: - fprintf(stderr, "[libretro]: Invalid device!\n"); + int offset = snes_devices[0] == RETRO_DEVICE_JOYPAD_MULTITAP ? 4 : 1; + switch (device) + { + case RETRO_DEVICE_JOYPAD: + S9xSetController(port, CTL_JOYPAD, port * offset, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_JOYPAD; + break; + case RETRO_DEVICE_JOYPAD_MULTITAP: + S9xSetController(port, CTL_MP5, port * offset, port * offset + 1, port * offset + 2, port * offset + 3); + snes_devices[port] = RETRO_DEVICE_JOYPAD_MULTITAP; + break; + case RETRO_DEVICE_MOUSE: + S9xSetController(port, CTL_MOUSE, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_MOUSE; + break; + case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: + S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE; + break; + case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: + S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIER; + break; + default: + if (log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Invalid device (%d).\n", device); + } + if (!port) + retro_set_controller_port_device(1, snes_devices[1]); } + else if(device != RETRO_DEVICE_NONE) + log_cb(RETRO_LOG_INFO, "[libretro]: Nonexistent Port (%d).\n", port); } void retro_cheat_reset() -{} +{ + S9xDeleteCheats(); + S9xApplyCheats(); +} -void retro_cheat_set(unsigned, bool, const char*) -{} +void retro_cheat_set(unsigned index, bool enabled, const char *code) +{ + uint32 address; + uint8 val; + + bool8 sram; + uint8 bytes[3];//used only by GoldFinger, ignored for now + + if (S9xGameGenieToRaw(code, address, val)!=NULL && + S9xProActionReplayToRaw(code, address, val)!=NULL && + S9xGoldFingerToRaw(code, address, sram, val, bytes)!=NULL) + { // bad code, ignore + return; + } + if (index>Cheat.num_cheats) return; // cheat added in weird order, ignore + if (index==Cheat.num_cheats) Cheat.num_cheats++; + + Cheat.c[index].address = address; + Cheat.c[index].byte = val; + Cheat.c[index].enabled = enabled; + + Cheat.c[index].saved = FALSE; // it'll be saved next time cheats run anyways + + Settings.ApplyCheats=true; + S9xApplyCheats(); +} bool retro_load_game(const struct retro_game_info *game) { - - if(game->data == NULL && game->size == NULL && game->path != NULL) + if(game->data == NULL && game->size == 0 && game->path != NULL) rom_loaded = Memory.LoadROM(game->path); else rom_loaded = Memory.LoadROMMem((const uint8_t*)game->data ,game->size); - if (!rom_loaded) - { - fprintf(stderr, "[libretro]: Rom loading failed...\n"); - } + if (!rom_loaded && log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Rom loading failed...\n"); return rom_loaded; } @@ -194,10 +319,8 @@ bool retro_load_game_special(unsigned game_type, rom_loaded = Memory.LoadROMMem((const uint8_t*)info[1].data,info[1].size); } - if (!rom_loaded) - { - fprintf(stderr, "[libretro]: BSX Rom loading failed...\n"); - } + if (!rom_loaded && log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: BSX ROM loading failed...\n"); break; @@ -205,12 +328,10 @@ bool retro_load_game_special(unsigned game_type, if(num_info == 2) rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[0].data, info[0].size, - (const uint8_t*)info[1].data, info[1].size, NULL, NULL); + (const uint8_t*)info[1].data, info[1].size, NULL, 0); - if (!rom_loaded) - { - fprintf(stderr, "[libretro]: Multirom loading failed...\n"); - } + if (!rom_loaded && log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Multirom loading failed...\n"); break; @@ -220,10 +341,8 @@ bool retro_load_game_special(unsigned game_type, rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[1].data, info[1].size, (const uint8_t*)info[2].data, info[2].size, (const uint8_t*)info[0].data, info[0].size); - if (!rom_loaded) - { - fprintf(stderr, "[libretro]: Sufami Turbo Rom loading failed...\n"); - } + if (!rom_loaded && log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Sufami Turbo ROM loading failed...\n"); break; @@ -240,12 +359,18 @@ static void map_buttons(); void retro_init() { + struct retro_log_callback log; if (environ_cb) { if (!environ_cb(RETRO_ENVIRONMENT_GET_OVERSCAN, &use_overscan)) use_overscan = false; } + if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + log_cb = log.log; + else + log_cb = NULL; + memset(&Settings, 0, sizeof(Settings)); Settings.MouseMaster = TRUE; Settings.SuperScopeMaster = TRUE; @@ -278,7 +403,9 @@ void retro_init() { Memory.Deinit(); S9xDeinitAPU(); - fprintf(stderr, "[libretro]: Failed to init Memory or APU.\n"); + + if (log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Failed to init Memory or APU.\n"); exit(1); } @@ -432,19 +559,20 @@ static int16_t snes_justifier_state[2][2] = {{0}, {0}}; static void report_buttons() { int _x, _y; + int offset = snes_devices[0] == RETRO_DEVICE_JOYPAD_MULTITAP ? 4 : 1; for (int port = 0; port <= 1; port++) { switch (snes_devices[port]) { case RETRO_DEVICE_JOYPAD: for (int i = BTN_FIRST; i <= BTN_LAST; i++) - S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, i)); + S9xReportButton(MAKE_BUTTON(port * offset + 1, i), s9x_input_state_cb(port * offset, RETRO_DEVICE_JOYPAD, 0, i)); break; case RETRO_DEVICE_JOYPAD_MULTITAP: for (int j = 0; j < 4; j++) for (int i = BTN_FIRST; i <= BTN_LAST; i++) - S9xReportButton(MAKE_BUTTON(j + 2, i), s9x_input_state_cb(port, RETRO_DEVICE_JOYPAD_MULTITAP, j, i)); + S9xReportButton(MAKE_BUTTON(port * offset + j + 1, i), s9x_input_state_cb(port * offset + j, RETRO_DEVICE_JOYPAD, 0, i)); break; case RETRO_DEVICE_MOUSE: @@ -458,24 +586,25 @@ static void report_buttons() break; case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: - snes_scope_state[0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_X); - snes_scope_state[1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); + snes_scope_state[0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_X); + snes_scope_state[1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); S9xReportPointer(BTN_POINTER, snes_scope_state[0], snes_scope_state[1]); for (int i = SCOPE_TRIGGER; i <= SCOPE_LAST; i++) - S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, i)); + S9xReportButton(MAKE_BUTTON(2, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, i)); break; case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS: - snes_justifier_state[0][0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_X); - snes_justifier_state[0][1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); + snes_justifier_state[0][0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_X); + snes_justifier_state[0][1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); S9xReportPointer(BTN_POINTER, snes_justifier_state[0][0], snes_justifier_state[0][1]); for (int i = JUSTIFIER_TRIGGER; i <= JUSTIFIER_LAST; i++) - S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, i)); + S9xReportButton(MAKE_BUTTON(2, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, i)); break; default: - fprintf(stderr, "[libretro]: Unknown device...\n"); + if (log_cb) + log_cb(RETRO_LOG_ERROR, "[libretro]: Unknown device...\n"); } } @@ -483,6 +612,10 @@ static void report_buttons() void retro_run() { + bool updated = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) + update_variables(); + s9x_poller_cb(); report_buttons(); S9xMainLoop(); @@ -494,6 +627,8 @@ void retro_deinit() Memory.Deinit(); S9xGraphicsDeinit(); S9xUnmapAllControls(); + + free(GFX.Screen); } @@ -531,11 +666,6 @@ void* retro_get_memory_data(unsigned type) return data; } -void retro_unload_cartridge() -{ - -} - size_t retro_get_memory_size(unsigned type) { size_t size; @@ -622,7 +752,7 @@ bool8 S9xDeinitUpdate(int width, int height) bool8 S9xContinueUpdate(int width, int height) { - return S9xDeinitUpdate(width, height); + return true; } // Dummy functions that should probably be implemented correctly later. diff --git a/libretro/libretro.def b/libretro/libretro.def index aa6381b4..77094e74 100644 --- a/libretro/libretro.def +++ b/libretro/libretro.def @@ -34,8 +34,6 @@ retro_load_game retro_unload_game retro_load_game_special -retro_unload_cartridge - retro_get_region retro_get_memory_data retro_get_memory_size \ No newline at end of file diff --git a/libretro/libretro.h b/libretro/libretro.h old mode 100644 new mode 100755 index 581023fe..80775167 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -1,15 +1,39 @@ +/* Copyright (C) 2010-2014 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef LIBRETRO_H__ #define LIBRETRO_H__ -#include "snes9x.h" +#include #include #include -// Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. #ifdef __cplusplus extern "C" { -#else -#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) && !defined(__cplusplus) +#endif + +#ifndef __cplusplus +#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) +/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */ #define bool unsigned char #define true 1 #define false 0 @@ -19,11 +43,25 @@ extern "C" { #endif // Used for checking API/ABI mismatches that can break libretro implementations. -// It is not incremented for compatible changes. +// It is not incremented for compatible changes to the API. #define RETRO_API_VERSION 1 -// Libretro's fundamental device abstractions. -#define RETRO_DEVICE_MASK 0xff +// +// Libretros fundamental device abstractions. +///////// +// +// Libretros input system consists of some standardized device types such as a joypad (with/without analog), +// mouse, keyboard, lightgun and a pointer. The functionality of these devices are fixed, and individual cores map +// their own concept of a controller to libretros abstractions. +// This makes it possible for frontends to map the abstract types to a real input device, +// and not having to worry about binding input correctly to arbitrary controller layouts. + + +#define RETRO_DEVICE_TYPE_SHIFT 8 +#define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1) +#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base) + +// Input disabled. #define RETRO_DEVICE_NONE 0 // The JOYPAD is called RetroPad. It is essentially a Super Nintendo controller, @@ -38,6 +76,7 @@ extern "C" { // KEYBOARD device lets one poll for raw key pressed. // It is poll based, so input callback will return with the current pressed state. +// For event/text based keyboard input, see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. #define RETRO_DEVICE_KEYBOARD 3 // Lightgun X/Y coordinates are reported relatively to last poll, similar to mouse. @@ -50,15 +89,27 @@ extern "C" { // Only use ANALOG type when polling for analog values of the axes. #define RETRO_DEVICE_ANALOG 5 -// These device types are specializations of the base types above. -// They should only be used in retro_set_controller_type() to inform libretro implementations -// about use of a very specific device type. +// Abstracts the concept of a pointing mechanism, e.g. touch. +// This allows libretro to query in absolute coordinates where on the screen a mouse (or something similar) is being placed. +// For a touch centric device, coordinates reported are the coordinates of the press. // -// In input state callback, however, only the base type should be used in the 'device' field. -#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD) -#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN) -#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN) -#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN) +// Coordinates in X and Y are reported as: +// [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen, +// and 0x7fff corresponds to the far right/bottom of the screen. +// The "screen" is here defined as area that is passed to the frontend and later displayed on the monitor. +// The frontend is free to scale/resize this screen as it sees fit, however, +// (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the game image, etc. +// +// To check if the pointer coordinates are valid (e.g. a touch display actually being touched), +// PRESSED returns 1 or 0. +// If using a mouse on a desktop, PRESSED will usually correspond to the left mouse button, but this is a frontend decision. +// PRESSED will only return 1 if the pointer is inside the game screen. +// +// For multi-touch, the index variable can be used to successively query more presses. +// If index = 0 returns true for _PRESSED, coordinates can be extracted +// with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with index = 1, and so on. +// Eventually _PRESSED will return false for an index. No further presses are registered at this point. +#define RETRO_DEVICE_POINTER 6 // Buttons for the RetroPad (JOYPAD). // The placement of these is equivalent to placements on the Super Nintendo controller. @@ -87,10 +138,13 @@ extern "C" { #define RETRO_DEVICE_ID_ANALOG_Y 1 // Id values for MOUSE. -#define RETRO_DEVICE_ID_MOUSE_X 0 -#define RETRO_DEVICE_ID_MOUSE_Y 1 -#define RETRO_DEVICE_ID_MOUSE_LEFT 2 -#define RETRO_DEVICE_ID_MOUSE_RIGHT 3 +#define RETRO_DEVICE_ID_MOUSE_X 0 +#define RETRO_DEVICE_ID_MOUSE_Y 1 +#define RETRO_DEVICE_ID_MOUSE_LEFT 2 +#define RETRO_DEVICE_ID_MOUSE_RIGHT 3 +#define RETRO_DEVICE_ID_MOUSE_WHEELUP 4 +#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5 +#define RETRO_DEVICE_ID_MOUSE_MIDDLE 6 // Id values for LIGHTGUN types. #define RETRO_DEVICE_ID_LIGHTGUN_X 0 @@ -101,6 +155,11 @@ extern "C" { #define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 #define RETRO_DEVICE_ID_LIGHTGUN_START 6 +// Id values for POINTER. +#define RETRO_DEVICE_ID_POINTER_X 0 +#define RETRO_DEVICE_ID_POINTER_Y 1 +#define RETRO_DEVICE_ID_POINTER_PRESSED 2 + // Returned from retro_get_region(). #define RETRO_REGION_NTSC 0 #define RETRO_REGION_PAL 1 @@ -111,7 +170,7 @@ extern "C" { // Regular save ram. This ram is usually found on a game cartridge, backed up by a battery. // If save game data is too complex for a single memory buffer, -// the SYSTEM_DIRECTORY environment callback can be used. +// the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment callback can be used. #define RETRO_MEMORY_SAVE_RAM 0 // Some games have a built-in clock to keep track of time. @@ -124,21 +183,6 @@ extern "C" { // Video ram lets a frontend peek into a game systems video RAM (VRAM). #define RETRO_MEMORY_VIDEO_RAM 3 -// Special memory types. -#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) -#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM) -#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) -#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM) -#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM) -#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC) - -// Special game types passed into retro_load_game_special(). -// Only used when multiple ROMs are required. -#define RETRO_GAME_TYPE_BSX 0x101 -#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102 -#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103 -#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104 - // Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. enum retro_key { @@ -285,9 +329,32 @@ enum retro_key RETROK_EURO = 321, RETROK_UNDO = 322, - RETROK_LAST + RETROK_LAST, + + RETROK_DUMMY = INT_MAX // Ensure sizeof(enum) == sizeof(int) }; +enum retro_mod +{ + RETROKMOD_NONE = 0x0000, + + RETROKMOD_SHIFT = 0x01, + RETROKMOD_CTRL = 0x02, + RETROKMOD_ALT = 0x04, + RETROKMOD_META = 0x08, + + RETROKMOD_NUMLOCK = 0x10, + RETROKMOD_CAPSLOCK = 0x20, + RETROKMOD_SCROLLOCK = 0x40, + + RETROKMOD_DUMMY = INT_MAX // Ensure sizeof(enum) == sizeof(int) +}; + +// If set, this call is not part of the public libretro API yet. It can change or be removed at any time. +#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 +// Environment callback to be used internally in frontend. +#define RETRO_ENVIRONMENT_PRIVATE 0x20000 + // Environment commands. #define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * -- // Sets screen rotation of graphics. @@ -302,21 +369,10 @@ enum retro_key // Boolean value whether or not frontend supports frame duping, // passing NULL to video frame callback. // -#define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * -- - // Interface to aquire user-defined information from environment - // that cannot feasibly be supported in a multi-system way. - // Mostly used for obscure, - // specific features that the user can tap into when neseccary. - // -#define RETRO_ENVIRONMENT_SET_VARIABLES 5 // const struct retro_variable * -- - // Allows an implementation to signal the environment - // which variables it might want to check for later using GET_VARIABLE. - // 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element. - // retro_variable::value should contain a human readable description of the key. - // +// Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), and reserved to avoid possible ABI clash. #define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * -- // Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'. - // Should not be used for trivial messages, which should simply be logged to stderr. + // Should not be used for trivial messages, which should simply be logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a fallback, stderr). #define RETRO_ENVIRONMENT_SHUTDOWN 7 // N/A (NULL) -- // Requests the frontend to shutdown. // Should only be used if game has a specific @@ -331,17 +387,12 @@ enum retro_key // // It can be used by the frontend to potentially warn // about too demanding implementations. - // - // The levels are "floating", but roughly defined as: - // 0: Low-powered embedded devices such as Raspberry Pi - // 1: 6th generation consoles, such as Wii/Xbox 1, and phones, tablets, etc. - // 2: 7th generation consoles, such as PS3/360, with sub-par CPUs. - // 3: Modern desktop/laptops with reasonably powerful CPUs. - // 4: High-end desktops with very powerful CPUs. + // + // The levels are "floating". // // This function can be called on a per-game basis, // as certain games an implementation can play might be - // particularily demanding. + // particularly demanding. // If called, it should be called in retro_load_game(). // #define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9 @@ -352,6 +403,9 @@ enum retro_key // If so, no such directory is defined, // and it's up to the implementation to find a suitable directory. // + // NOTE: Some cores used this folder also for "save" data such as memory cards, etc, for lack of a better place to put it. + // This is now discouraged, and if possible, cores should try to use the new GET_SAVE_DIRECTORY. + // #define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 // const enum retro_pixel_format * -- // Sets the internal pixel format used by the implementation. @@ -366,7 +420,695 @@ enum retro_key // It is up to the frontend to present this in a usable way. // The array is terminated by retro_input_descriptor::description being set to NULL. // This function can be called at any time, but it is recommended to call it as early as possible. +#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 + // const struct retro_keyboard_callback * -- + // Sets a callback function used to notify core about keyboard events. + // +#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 + // const struct retro_disk_control_callback * -- + // Sets an interface which frontend can use to eject and insert disk images. + // This is used for games which consist of multiple images and must be manually + // swapped out by the user (e.g. PSX). +#define RETRO_ENVIRONMENT_SET_HW_RENDER 14 + // struct retro_hw_render_callback * -- + // Sets an interface to let a libretro core render with hardware acceleration. + // Should be called in retro_load_game(). + // If successful, libretro cores will be able to render to a frontend-provided framebuffer. + // The size of this framebuffer will be at least as large as max_width/max_height provided in get_av_info(). + // If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or NULL to retro_video_refresh_t. +#define RETRO_ENVIRONMENT_GET_VARIABLE 15 + // struct retro_variable * -- + // Interface to acquire user-defined information from environment + // that cannot feasibly be supported in a multi-system way. + // 'key' should be set to a key which has already been set by SET_VARIABLES. + // 'data' will be set to a value or NULL. + // +#define RETRO_ENVIRONMENT_SET_VARIABLES 16 + // const struct retro_variable * -- + // Allows an implementation to signal the environment + // which variables it might want to check for later using GET_VARIABLE. + // This allows the frontend to present these variables to a user dynamically. + // This should be called as early as possible (ideally in retro_set_environment). + // + // 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element. + // retro_variable::key should be namespaced to not collide with other implementations' keys. E.g. A core called 'foo' should use keys named as 'foo_option'. + // retro_variable::value should contain a human readable description of the key as well as a '|' delimited list of expected values. + // The number of possible options should be very limited, i.e. it should be feasible to cycle through options without a keyboard. + // First entry should be treated as a default. + // + // Example entry: + // { "foo_option", "Speed hack coprocessor X; false|true" } + // + // Text before first ';' is description. This ';' must be followed by a space, and followed by a list of possible values split up with '|'. + // Only strings are operated on. The possible values will generally be displayed and stored as-is by the frontend. + // +#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17 + // bool * -- + // Result is set to true if some variables are updated by + // frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. + // Variables should be queried with GET_VARIABLE. + // +#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 + // const bool * -- + // If true, the libretro implementation supports calls to retro_load_game() with NULL as argument. + // Used by cores which can run without particular game data. + // This should be called within retro_set_environment() only. + // +#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 + // const char ** -- + // Retrieves the absolute path from where this libretro implementation was loaded. + // NULL is returned if the libretro was loaded statically (i.e. linked statically to frontend), or if the path cannot be determined. + // Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can be loaded without ugly hacks. + // + // +// Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. It was not used by any known core at the time, +// and was removed from the API. +#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 + // const struct retro_audio_callback * -- + // Sets an interface which is used to notify a libretro core about audio being available for writing. + // The callback can be called from any thread, so a core using this must have a thread safe audio implementation. + // It is intended for games where audio and video are completely asynchronous and audio can be generated on the fly. + // This interface is not recommended for use with emulators which have highly synchronous audio. + // + // The callback only notifies about writability; the libretro core still has to call the normal audio callbacks + // to write audio. The audio callbacks must be called from within the notification callback. + // The amount of audio data to write is up to the implementation. + // Generally, the audio callback will be called continously in a loop. + // + // Due to thread safety guarantees and lack of sync between audio and video, a frontend + // can selectively disallow this interface based on internal configuration. A core using + // this interface must also implement the "normal" audio interface. + // + // A libretro core using SET_AUDIO_CALLBACK should also make use of SET_FRAME_TIME_CALLBACK. +#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 + // const struct retro_frame_time_callback * -- + // Lets the core know how much time has passed since last invocation of retro_run(). + // The frontend can tamper with the timing to fake fast-forward, slow-motion, frame stepping, etc. + // In this case the delta time will use the reference value in frame_time_callback.. + // +#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 + // struct retro_rumble_interface * -- + // Gets an interface which is used by a libretro core to set state of rumble motors in controllers. + // A strong and weak motor is supported, and they can be controlled indepedently. + // +#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 + // uint64_t * -- + // Gets a bitmask telling which device type are expected to be handled properly in a call to retro_input_state_t. + // Devices which are not handled or recognized always return 0 in retro_input_state_t. + // Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). + // Should only be called in retro_run(). + // +#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) + // struct retro_sensor_interface * -- + // Gets access to the sensor interface. + // The purpose of this interface is to allow + // setting state related to sensors such as polling rate, enabling/disable it entirely, etc. + // Reading sensor state is done via the normal input_state_callback API. + // +#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) + // struct retro_camera_callback * -- + // Gets an interface to a video camera driver. + // A libretro core can use this interface to get access to a video camera. + // New video frames are delivered in a callback in same thread as retro_run(). + // + // GET_CAMERA_INTERFACE should be called in retro_load_game(). + // + // Depending on the camera implementation used, camera frames will be delivered as a raw framebuffer, + // or as an OpenGL texture directly. + // + // The core has to tell the frontend here which types of buffers can be handled properly. + // An OpenGL texture can only be handled when using a libretro GL core (SET_HW_RENDER). + // It is recommended to use a libretro GL core when using camera interface. + // + // The camera is not started automatically. The retrieved start/stop functions must be used to explicitly + // start and stop the camera driver. + // +#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 + // struct retro_log_callback * -- + // Gets an interface for logging. This is useful for logging in a cross-platform way + // as certain platforms cannot use use stderr for logging. It also allows the frontend to + // show logging information in a more suitable way. + // If this interface is not used, libretro cores should log to stderr as desired. +#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28 + // struct retro_perf_callback * -- + // Gets an interface for performance counters. This is useful for performance logging in a + // cross-platform way and for detecting architecture-specific features, such as SIMD support. +#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29 + // struct retro_location_callback * -- + // Gets access to the location interface. + // The purpose of this interface is to be able to retrieve location-based information from the host device, + // such as current latitude / longitude. + // +#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 + // const char ** -- + // Returns the "content" directory of the frontend. + // This directory can be used to store specific assets that the core relies upon, such as art assets, + // input data, etc etc. + // The returned value can be NULL. + // If so, no such directory is defined, + // and it's up to the implementation to find a suitable directory. + // +#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 + // const char ** -- + // Returns the "save" directory of the frontend. + // This directory can be used to store SRAM, memory cards, high scores, etc, if the libretro core + // cannot use the regular memory interface (retro_get_memory_data()). + // + // NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for similar things before. + // They should still check GET_SYSTEM_DIRECTORY if they want to be backwards compatible. + // The path here can be NULL. It should only be non-NULL if the frontend user has set a specific save path. + // +#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 + // const struct retro_system_av_info * -- + // Sets a new av_info structure. This can only be called from within retro_run(). + // This should *only* be used if the core is completely altering the internal resolutions, aspect ratios, timings, sampling rate, etc. + // Calling this can require a full reinitialization of video/audio drivers in the frontend, + // so it is important to call it very sparingly, and usually only with the users explicit consent. + // An eventual driver reinitialize will happen so that video and audio callbacks + // happening after this call within the same retro_run() call will target the newly initialized driver. + // + // This callback makes it possible to support configurable resolutions in games, which can be useful to + // avoid setting the "worst case" in max_width/max_height. + // + // ***HIGHLY RECOMMENDED*** Do not call this callback every time resolution changes in an emulator core if it's + // expected to be a temporary change, for the reasons of possible driver reinit. + // This call is not a free pass for not trying to provide correct values in retro_get_system_av_info(). + // + // If this returns false, the frontend does not acknowledge a changed av_info struct. +#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 + // const struct retro_get_proc_address_interface * -- + // Allows a libretro core to announce support for the get_proc_address() interface. + // This interface allows for a standard way to extend libretro where use of environment calls are too indirect, + // e.g. for cases where the frontend wants to call directly into the core. + // + // If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK **MUST** be called from within retro_set_environment(). + // +#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34 + // const struct retro_subsystem_info * -- + // This environment call introduces the concept of libretro "subsystems". + // A subsystem is a variant of a libretro core which supports different kinds of games. + // The purpose of this is to support e.g. emulators which might have special needs, e.g. Super Nintendos Super GameBoy, Sufami Turbo. + // It can also be used to pick among subsystems in an explicit way if the libretro implementation is a multi-system emulator itself. + // + // Loading a game via a subsystem is done with retro_load_game_special(), + // and this environment call allows a libretro core to expose which subsystems are supported for use with retro_load_game_special(). + // A core passes an array of retro_game_special_info which is terminated with a zeroed out retro_game_special_info struct. + // + // If a core wants to use this functionality, SET_SUBSYSTEM_INFO **MUST** be called from within retro_set_environment(). + // +#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 + // const struct retro_controller_info * -- + // This environment call lets a libretro core tell the frontend which + // controller types are recognized in calls to retro_set_controller_port_device(). + // + // Some emulators such as Super Nintendo + // support multiple lightgun types which must be specifically selected from. + // It is therefore sometimes necessary for a frontend to be able to tell + // the core about a special kind of input device which is not covered by the + // libretro input API. + // + // In order for a frontend to understand the workings of an input device, + // it must be a specialized type + // of the generic device types already defined in the libretro API. + // + // Which devices are supported can vary per input port. + // The core must pass an array of const struct retro_controller_info which is terminated with + // a blanked out struct. Each element of the struct corresponds to an ascending port index to retro_set_controller_port_device(). + // Even if special device types are set in the libretro core, libretro should only poll input based on the base input device types. +struct retro_controller_description +{ + // Human-readable description of the controller. Even if using a generic input device type, this can be + // set to the particular device type the core uses. + const char *desc; + + // Device type passed to retro_set_controller_port_device(). If the device type is a sub-class of a generic input device type, + // use the RETRO_DEVICE_SUBCLASS macro to create an ID. E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). + unsigned id; +}; + +struct retro_controller_info +{ + const struct retro_controller_description *types; + unsigned num_types; +}; + +struct retro_subsystem_memory_info +{ + const char *extension; // The extension associated with a memory type, e.g. "psram". + unsigned type; // The memory type for retro_get_memory(). This should be at least 0x100 to avoid conflict with standardized libretro memory types. +}; + +struct retro_subsystem_rom_info +{ + const char *desc; // Describes what the ROM is (SGB bios, GB rom, etc). + const char *valid_extensions; // Same definition as retro_get_system_info(). + bool need_fullpath; // Same definition as retro_get_system_info(). + bool block_extract; // Same definition as retro_get_system_info(). + bool required; // This is set if the ROM is required to load a game. If this is set to false, a zeroed-out retro_game_info can be passed. + + // ROMs can have multiple associated persistent memory types (retro_get_memory()). + const struct retro_subsystem_memory_info *memory; + unsigned num_memory; +}; + +struct retro_subsystem_info +{ + const char *desc; // Human-readable string of the subsystem type, e.g. "Super GameBoy" + // A computer friendly short string identifier for the subsystem type. + // This name must be [a-z]. + // E.g. if desc is "Super GameBoy", this can be "sgb". + // This identifier can be used for command-line interfaces, etc. + const char *ident; + + // Infos for each ROM. The first entry is assumed to be the "most significant" ROM for frontend purposes. + // E.g. with Super GameBoy, the first ROM should be the GameBoy ROM, as it is the most "significant" ROM to a user. + // If a frontend creates new file paths based on the ROM used (e.g. savestates), it should use the path for the first ROM to do so. + const struct retro_subsystem_rom_info *roms; + + unsigned num_roms; // Number of ROMs associated with a subsystem. + unsigned id; // The type passed to retro_load_game_special(). +}; + +typedef void (*retro_proc_address_t)(void); +// libretro API extension functions: +// (None here so far). +////// + +// Get a symbol from a libretro core. +// Cores should only return symbols which are actual extensions to the libretro API. +// Frontends should not use this to obtain symbols to standard libretro entry points (static linking or dlsym). +// The symbol name must be equal to the function name, e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo". +// The returned function pointer must be cast to the corresponding type. +typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym); +struct retro_get_proc_address_interface +{ + retro_get_proc_address_t get_proc_address; +}; + +enum retro_log_level +{ + RETRO_LOG_DEBUG = 0, + RETRO_LOG_INFO, + RETRO_LOG_WARN, + RETRO_LOG_ERROR, + + RETRO_LOG_DUMMY = INT_MAX +}; + +// Logging function. Takes log level argument as well. +typedef void (*retro_log_printf_t)(enum retro_log_level level, const char *fmt, ...); + +struct retro_log_callback +{ + retro_log_printf_t log; +}; + +// Performance related functions +// +// ID values for SIMD CPU features +#define RETRO_SIMD_SSE (1 << 0) +#define RETRO_SIMD_SSE2 (1 << 1) +#define RETRO_SIMD_VMX (1 << 2) +#define RETRO_SIMD_VMX128 (1 << 3) +#define RETRO_SIMD_AVX (1 << 4) +#define RETRO_SIMD_NEON (1 << 5) +#define RETRO_SIMD_SSE3 (1 << 6) +#define RETRO_SIMD_SSSE3 (1 << 7) +#define RETRO_SIMD_MMX (1 << 8) +#define RETRO_SIMD_MMXEXT (1 << 9) +#define RETRO_SIMD_SSE4 (1 << 10) +#define RETRO_SIMD_SSE42 (1 << 11) +#define RETRO_SIMD_AVX2 (1 << 12) +#define RETRO_SIMD_VFPU (1 << 13) +#define RETRO_SIMD_PS (1 << 14) + +typedef uint64_t retro_perf_tick_t; +typedef int64_t retro_time_t; + +struct retro_perf_counter +{ + const char *ident; + retro_perf_tick_t start; + retro_perf_tick_t total; + retro_perf_tick_t call_cnt; + + bool registered; +}; + +// Returns current time in microseconds. Tries to use the most accurate timer available. +typedef retro_time_t (*retro_perf_get_time_usec_t)(void); +// A simple counter. Usually nanoseconds, but can also be CPU cycles. +// Can be used directly if desired (when creating a more sophisticated performance counter system). +typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void); +// Returns a bit-mask of detected CPU features (RETRO_SIMD_*). +typedef uint64_t (*retro_get_cpu_features_t)(void); +// Asks frontend to log and/or display the state of performance counters. +// Performance counters can always be poked into manually as well. +typedef void (*retro_perf_log_t)(void); +// Register a performance counter. +// ident field must be set with a discrete value and other values in retro_perf_counter must be 0. +// Registering can be called multiple times. To avoid calling to frontend redundantly, you can check registered field first. +typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter); +// Starts and stops a registered counter. +typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter); +typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter); + +// For convenience it can be useful to wrap register, start and stop in macros. +// E.g.: +// #ifdef LOG_PERFORMANCE +// #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name)) +// #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name)) +// #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name)) +// #else +// ... Blank macros ... +// #endif +// These can then be used mid-functions around code snippets. +// +// extern struct retro_perf_callback perf_cb; // Somewhere in the core. +// +// void do_some_heavy_work(void) +// { +// RETRO_PERFORMANCE_INIT(cb, work_1); +// RETRO_PERFORMANCE_START(cb, work_1); +// heavy_work_1(); +// RETRO_PERFORMANCE_STOP(cb, work_1); +// +// RETRO_PERFORMANCE_INIT(cb, work_2); +// RETRO_PERFORMANCE_START(cb, work_2); +// heavy_work_2(); +// RETRO_PERFORMANCE_STOP(cb, work_2); +// } +// +// void retro_deinit(void) +// { +// perf_cb.perf_log(); // Log all perf counters here for example. +// } + +struct retro_perf_callback +{ + retro_perf_get_time_usec_t get_time_usec; + retro_get_cpu_features_t get_cpu_features; + + retro_perf_get_counter_t get_perf_counter; + retro_perf_register_t perf_register; + retro_perf_start_t perf_start; + retro_perf_stop_t perf_stop; + retro_perf_log_t perf_log; +}; + +// FIXME: Document the sensor API and work out behavior. +// It will be marked as experimental until then. +enum retro_sensor_action +{ + RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, + RETRO_SENSOR_ACCELEROMETER_DISABLE, + + RETRO_SENSOR_DUMMY = INT_MAX +}; + +// Id values for SENSOR types. +#define RETRO_SENSOR_ACCELEROMETER_X 0 +#define RETRO_SENSOR_ACCELEROMETER_Y 1 +#define RETRO_SENSOR_ACCELEROMETER_Z 2 + +typedef bool (*retro_set_sensor_state_t)(unsigned port, enum retro_sensor_action action, unsigned rate); +typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id); +struct retro_sensor_interface +{ + retro_set_sensor_state_t set_sensor_state; + retro_sensor_get_input_t get_sensor_input; +}; +//// + +enum retro_camera_buffer +{ + RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, + RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, + + RETRO_CAMERA_BUFFER_DUMMY = INT_MAX +}; + +// Starts the camera driver. Can only be called in retro_run(). +typedef bool (*retro_camera_start_t)(void); +// Stops the camera driver. Can only be called in retro_run(). +typedef void (*retro_camera_stop_t)(void); +// Callback which signals when the camera driver is initialized and/or deinitialized. +// retro_camera_start_t can be called in initialized callback. +typedef void (*retro_camera_lifetime_status_t)(void); +// A callback for raw framebuffer data. buffer points to an XRGB8888 buffer. +// Width, height and pitch are similar to retro_video_refresh_t. +// First pixel is top-left origin. +typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, unsigned width, unsigned height, size_t pitch); +// A callback for when OpenGL textures are used. +// +// texture_id is a texture owned by camera driver. +// Its state or content should be considered immutable, except for things like texture filtering and clamping. +// +// texture_target is the texture target for the GL texture. +// These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly more depending on extensions. +// +// affine points to a packed 3x3 column-major matrix used to apply an affine transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0)) +// After transform, normalized texture coord (0, 0) should be bottom-left and (1, 1) should be top-right (or (width, height) for RECTANGLE). +// +// GL-specific typedefs are avoided here to avoid relying on gl.h in the API definition. +typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id, unsigned texture_target, const float *affine); +struct retro_camera_callback +{ + uint64_t caps; // Set by libretro core. Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). + + unsigned width; // Desired resolution for camera. Is only used as a hint. + unsigned height; + retro_camera_start_t start; // Set by frontend. + retro_camera_stop_t stop; // Set by frontend. + + retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; // Set by libretro core if raw framebuffer callbacks will be used. + retro_camera_frame_opengl_texture_t frame_opengl_texture; // Set by libretro core if OpenGL texture callbacks will be used. + + // Set by libretro core. Called after camera driver is initialized and ready to be started. + // Can be NULL, in which this callback is not called. + retro_camera_lifetime_status_t initialized; + + // Set by libretro core. Called right before camera driver is deinitialized. + // Can be NULL, in which this callback is not called. + retro_camera_lifetime_status_t deinitialized; +}; + +// Sets the interval of time and/or distance at which to update/poll location-based data. +// To ensure compatibility with all location-based implementations, values for both +// interval_ms and interval_distance should be provided. +// interval_ms is the interval expressed in milliseconds. +// interval_distance is the distance interval expressed in meters. +typedef void (*retro_location_set_interval_t)(unsigned interval_ms, unsigned interval_distance); + +// Start location services. The device will start listening for changes to the +// current location at regular intervals (which are defined with retro_location_set_interval_t). +typedef bool (*retro_location_start_t)(void); + +// Stop location services. The device will stop listening for changes to the current +// location. +typedef void (*retro_location_stop_t)(void); + +// Get the position of the current location. Will set parameters to 0 if no new +// location update has happened since the last time. +typedef bool (*retro_location_get_position_t)(double *lat, double *lon, double *horiz_accuracy, + double *vert_accuracy); + +// Callback which signals when the location driver is initialized and/or deinitialized. +// retro_location_start_t can be called in initialized callback. +typedef void (*retro_location_lifetime_status_t)(void); + +struct retro_location_callback +{ + retro_location_start_t start; + retro_location_stop_t stop; + retro_location_get_position_t get_position; + retro_location_set_interval_t set_interval; + + retro_location_lifetime_status_t initialized; + retro_location_lifetime_status_t deinitialized; +}; + +enum retro_rumble_effect +{ + RETRO_RUMBLE_STRONG = 0, + RETRO_RUMBLE_WEAK = 1, + + RETRO_RUMBLE_DUMMY = INT_MAX +}; + +// Sets rumble state for joypad plugged in port 'port'. Rumble effects are controlled independently, +// and setting e.g. strong rumble does not override weak rumble. +// Strength has a range of [0, 0xffff]. +// +// Returns true if rumble state request was honored. Calling this before first retro_run() is likely to return false. +typedef bool (*retro_set_rumble_state_t)(unsigned port, enum retro_rumble_effect effect, uint16_t strength); +struct retro_rumble_interface +{ + retro_set_rumble_state_t set_rumble_state; +}; + +// Notifies libretro that audio data should be written. +typedef void (*retro_audio_callback_t)(void); + +// True: Audio driver in frontend is active, and callback is expected to be called regularily. +// False: Audio driver in frontend is paused or inactive. Audio callback will not be called until set_state has been called with true. +// Initial state is false (inactive). +typedef void (*retro_audio_set_state_callback_t)(bool enabled); +struct retro_audio_callback +{ + retro_audio_callback_t callback; + retro_audio_set_state_callback_t set_state; +}; + +// Notifies a libretro core of time spent since last invocation of retro_run() in microseconds. +// It will be called right before retro_run() every frame. +// The frontend can tamper with timing to support cases like fast-forward, slow-motion and framestepping. +// In those scenarios the reference frame time value will be used. +typedef int64_t retro_usec_t; +typedef void (*retro_frame_time_callback_t)(retro_usec_t usec); +struct retro_frame_time_callback +{ + retro_frame_time_callback_t callback; + retro_usec_t reference; // Represents the time of one frame. It is computed as 1000000 / fps, but the implementation will resolve the rounding to ensure that framestepping, etc is exact. +}; + +// Pass this to retro_video_refresh_t if rendering to hardware. +// Passing NULL to retro_video_refresh_t is still a frame dupe as normal. +#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1) + +// Invalidates the current HW context. +// Any GL state is lost, and must not be deinitialized explicitly. If explicit deinitialization is desired by the libretro core, +// it should implement context_destroy callback. +// If called, all GPU resources must be reinitialized. +// Usually called when frontend reinits video driver. +// Also called first time video driver is initialized, allowing libretro core to initialize resources. +typedef void (*retro_hw_context_reset_t)(void); +// Gets current framebuffer which is to be rendered to. Could change every frame potentially. +typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void); + +// Get a symbol from HW context. +typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym); + +enum retro_hw_context_type +{ + RETRO_HW_CONTEXT_NONE = 0, + RETRO_HW_CONTEXT_OPENGL = 1, // OpenGL 2.x. Driver can choose to use latest compatibility context. + RETRO_HW_CONTEXT_OPENGLES2 = 2, // GLES 2.0 + RETRO_HW_CONTEXT_OPENGL_CORE = 3, // Modern desktop core GL context. Use version_major/version_minor fields to set GL version. + RETRO_HW_CONTEXT_OPENGLES3 = 4, // GLES 3.0 + RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, // GLES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, use the corresponding enums directly. + + RETRO_HW_CONTEXT_DUMMY = INT_MAX +}; + +struct retro_hw_render_callback +{ + enum retro_hw_context_type context_type; // Which API to use. Set by libretro core. + + // Called when a context has been created or when it has been reset. + // An OpenGL context is only valid after context_reset() has been called. + // + // When context_reset is called, OpenGL resources in the libretro implementation are guaranteed to be invalid. + // It is possible that context_reset is called multiple times during an application lifecycle. + // If context_reset is called without any notification (context_destroy), + // the OpenGL context was lost and resources should just be recreated + // without any attempt to "free" old resources. + retro_hw_context_reset_t context_reset; + + retro_hw_get_current_framebuffer_t get_current_framebuffer; // Set by frontend. + retro_hw_get_proc_address_t get_proc_address; // Set by frontend. + bool depth; // Set if render buffers should have depth component attached. + bool stencil; // Set if stencil buffers should be attached. + // If depth and stencil are true, a packed 24/8 buffer will be added. Only attaching stencil is invalid and will be ignored. + bool bottom_left_origin; // Use conventional bottom-left origin convention. Is false, standard libretro top-left origin semantics are used. + unsigned version_major; // Major version number for core GL context or GLES 3.1+. + unsigned version_minor; // Minor version number for core GL context or GLES 3.1+. + + bool cache_context; // If this is true, the frontend will go very far to avoid resetting context in scenarios like toggling fullscreen, etc. + // The reset callback might still be called in extreme situations such as if the context is lost beyond recovery. + // For optimal stability, set this to false, and allow context to be reset at any time. + + retro_hw_context_reset_t context_destroy; // A callback to be called before the context is destroyed in a controlled way by the frontend. + // OpenGL resources can be deinitialized cleanly at this step. + // context_destroy can be set to NULL, in which resources will just be destroyed without any notification. + // + // Even when context_destroy is non-NULL, it is possible that context_reset is called without any destroy notification. + // This happens if context is lost by external factors (such as notified by GL_ARB_robustness). + // In this case, the context is assumed to be already dead, + // and the libretro implementation must not try to free any OpenGL resources in the subsequent context_reset. + + bool debug_context; // Creates a debug context. +}; + +// Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events. +// down is set if the key is being pressed, or false if it is being released. +// keycode is the RETROK value of the char. +// character is the text character of the pressed key. (UTF-32). +// key_modifiers is a set of RETROKMOD values or'ed together. +// +// The pressed/keycode state can be indepedent of the character. +// It is also possible that multiple characters are generated from a single keypress. +// Keycode events should be treated separately from character events. +// However, when possible, the frontend should try to synchronize these. +// If only a character is posted, keycode should be RETROK_UNKNOWN. +// Similarily if only a keycode event is generated with no corresponding character, character should be 0. +typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); + +struct retro_keyboard_callback +{ + retro_keyboard_event_t callback; +}; + +// Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. +// Should be set for implementations which can swap out multiple disk images in runtime. +// If the implementation can do this automatically, it should strive to do so. +// However, there are cases where the user must manually do so. +// +// Overview: To swap a disk image, eject the disk image with set_eject_state(true). +// Set the disk index with set_image_index(index). Insert the disk again with set_eject_state(false). + +// If ejected is true, "ejects" the virtual disk tray. +// When ejected, the disk image index can be set. +typedef bool (*retro_set_eject_state_t)(bool ejected); +// Gets current eject state. The initial state is 'not ejected'. +typedef bool (*retro_get_eject_state_t)(void); +// Gets current disk index. First disk is index 0. +// If return value is >= get_num_images(), no disk is currently inserted. +typedef unsigned (*retro_get_image_index_t)(void); +// Sets image index. Can only be called when disk is ejected. +// The implementation supports setting "no disk" by using an index >= get_num_images(). +typedef bool (*retro_set_image_index_t)(unsigned index); +// Gets total number of images which are available to use. +typedef unsigned (*retro_get_num_images_t)(void); +// +// Replaces the disk image associated with index. +// Arguments to pass in info have same requirements as retro_load_game(). +// Virtual disk tray must be ejected when calling this. +// Replacing a disk image with info = NULL will remove the disk image from the internal list. +// As a result, calls to get_image_index() can change. +// +// E.g. replace_image_index(1, NULL), and previous get_image_index() returned 4 before. +// Index 1 will be removed, and the new index is 3. +struct retro_game_info; +typedef bool (*retro_replace_image_index_t)(unsigned index, const struct retro_game_info *info); +// Adds a new valid index (get_num_images()) to the internal disk list. +// This will increment subsequent return values from get_num_images() by 1. +// This image index cannot be used until a disk image has been set with replace_image_index. +typedef bool (*retro_add_image_index_t)(void); + +struct retro_disk_control_callback +{ + retro_set_eject_state_t set_eject_state; + retro_get_eject_state_t get_eject_state; + + retro_get_image_index_t get_image_index; + retro_set_image_index_t set_image_index; + retro_get_num_images_t get_num_images; + + retro_replace_image_index_t replace_image_index; + retro_add_image_index_t add_image_index; +}; enum retro_pixel_format { @@ -526,6 +1268,8 @@ void retro_get_system_info(struct retro_system_info *info); void retro_get_system_av_info(struct retro_system_av_info *info); // Sets device to be used for player 'port'. +// By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all available ports. +// Setting a particular device type is not a guarantee that libretro cores will only poll input based on that particular device type. It is only a hint to the libretro core when a core cannot automatically detect the appropriate input device type on its own. It is also relevant when a core can change its behavior depending on device type. void retro_set_controller_port_device(unsigned port, unsigned device); // Resets the current game. diff --git a/memmap.cpp b/memmap.cpp index 8a135d63..85d08f62 100644 --- a/memmap.cpp +++ b/memmap.cpp @@ -188,6 +188,8 @@ #include "jma/s9x-jma.h" #endif +#include + #include "snes9x.h" #include "memmap.h" #include "apu/apu.h" @@ -1520,7 +1522,7 @@ bool8 CMemory::LoadROMMem (const uint8 *source, uint32 sourceSize) do { memset(ROM,0, MAX_ROM_SIZE); - memset(&Multi, 0,sizeof(Multi)); + memset(&Multi, 0,sizeof(Multi)); memcpy(ROM,source,sourceSize); } while(!LoadROMInt(sourceSize)); @@ -1538,14 +1540,14 @@ bool8 CMemory::LoadROM (const char *filename) do { memset(ROM,0, MAX_ROM_SIZE); - memset(&Multi, 0,sizeof(Multi)); + memset(&Multi, 0,sizeof(Multi)); totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE); if (!totalFileSize) - return (FALSE); + return (FALSE); if (!Settings.NoPatch) - CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize); + CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize); } while(!LoadROMInt(totalFileSize)); @@ -3371,7 +3373,7 @@ uint16 CMemory::checksum_calc_sum (uint8 *data, uint32 length) uint16 CMemory::checksum_mirror_sum (uint8 *start, uint32 &length, uint32 mask) { // from NSRT - while (!(length & mask)) + while (!(length & mask) && mask) mask >>= 1; uint16 part1 = checksum_calc_sum(start, mask); diff --git a/port.h b/port.h index 6c4559ea..b9653552 100644 --- a/port.h +++ b/port.h @@ -334,7 +334,7 @@ void SetInfoDlgColor(unsigned char, unsigned char, unsigned char); #define TITLE "Snes9x" #endif -#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || defined(_XBOX1) +#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || defined(_XBOX1) || defined(ARM) || defined(ANDROID) #define LSB_FIRST #define FAST_LSB_WORD_ACCESS #else diff --git a/snapshot.h b/snapshot.h index 88798a23..a234b8d8 100644 --- a/snapshot.h +++ b/snapshot.h @@ -179,6 +179,8 @@ #ifndef _SNAPSHOT_H_ #define _SNAPSHOT_H_ +#include "snes9x.h" + #define SNAPSHOT_MAGIC "#!s9xsnp" #define SNAPSHOT_VERSION_IRQ 7 #define SNAPSHOT_VERSION_BAPU 8 diff --git a/unzip/miniunz.c b/unzip/miniunz.c index b5bc8b54..db1ddd4f 100644 --- a/unzip/miniunz.c +++ b/unzip/miniunz.c @@ -215,11 +215,13 @@ int do_list(uf) else if ((iLevel==2) || (iLevel==3)) string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ } +#ifdef HAVE_BZIP2 else if (file_info.compression_method==Z_BZIP2ED) { string_method="BZip2 "; } +#endif else string_method="Unkn. "; diff --git a/unzip/unzip.c b/unzip/unzip.c index 17d730d6..6ec52096 100644 --- a/unzip/unzip.c +++ b/unzip/unzip.c @@ -1013,9 +1013,9 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && -/* #ifdef HAVE_BZIP2 */ +#ifdef HAVE_BZIP2 (s->cur_file_info.compression_method!=Z_BZIP2ED) && -/* #endif */ +#endif (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; @@ -1130,9 +1130,9 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) } if ((s->cur_file_info.compression_method!=0) && -/* #ifdef HAVE_BZIP2 */ +#ifdef HAVE_BZIP2 (s->cur_file_info.compression_method!=Z_BZIP2ED) && -/* #endif */ +#endif (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; @@ -1146,10 +1146,10 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) pfile_in_zip_read_info->stream.total_out = 0; +#ifdef HAVE_BZIP2 if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) { -#ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; @@ -1169,11 +1169,9 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) TRYFREE(pfile_in_zip_read_info); return err; } -#else - pfile_in_zip_read_info->raw=1; -#endif } else +#endif if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { @@ -1385,10 +1383,10 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len) pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } +#ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { -#ifdef HAVE_BZIP2 uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; @@ -1430,8 +1428,8 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len) return (iRead==0) ? UNZ_EOF : iRead; if (err!=BZ_OK) break; -#endif } +#endif else { uLong uTotalOutBefore,uTotalOutAfter; diff --git a/win32/CCGShader.cpp b/win32/CCGShader.cpp index 7789e321..cc1a8f4b 100644 --- a/win32/CCGShader.cpp +++ b/win32/CCGShader.cpp @@ -274,6 +274,13 @@ bool CCGShader::LoadShader(const char *path) sprintf(keyName,"::shader%u",i); strcpy(pass.cgShaderFile,conf.GetString(keyName,"")); + + sprintf(keyName,"::frame_count_mod%u",i); + pass.frameCounterMod = conf.GetInt(keyName,0); + + sprintf(keyName,"::float_framebuffer%u",i); + pass.floatFbo = conf.GetBool(keyName); + shaderPasses.push_back(pass); } diff --git a/win32/CCGShader.h b/win32/CCGShader.h index ab878bdf..a0d49dea 100644 --- a/win32/CCGShader.h +++ b/win32/CCGShader.h @@ -200,6 +200,8 @@ public: cgScaleParams scaleParams; bool linearFilter; bool filterSet; + bool floatFbo; + unsigned frameCounterMod; char cgShaderFile[PATH_MAX]; } shaderPass; typedef struct _lookupTexture { diff --git a/win32/CD3DCG.cpp b/win32/CD3DCG.cpp index 31535c34..c4b7cd51 100644 --- a/win32/CD3DCG.cpp +++ b/win32/CD3DCG.cpp @@ -332,6 +332,10 @@ bool CD3DCG::LoadShader(const TCHAR *shaderFile) pass.linearFilter = it->linearFilter; } + pass.frameCounterMod = it->frameCounterMod; + + pass.useFloatTex = it->floatFbo; + // paths in the meta file can be relative _tfullpath(tempPath,_tFromChar(it->cgShaderFile),MAX_PATH); char *fileContents = ReadShaderFileContents(tempPath); @@ -413,7 +417,7 @@ bool CD3DCG::LoadShader(const TCHAR *shaderFile) } void CD3DCG::ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, - D3DXVECTOR2 wantedSize,bool renderTarget) + D3DXVECTOR2 wantedSize,bool renderTarget,bool useFloat) { HRESULT hr; @@ -425,7 +429,7 @@ void CD3DCG::ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, (UINT)wantedSize.x, (UINT)wantedSize.y, 1, // 1 level, no mipmaps renderTarget?D3DUSAGE_RENDERTARGET:0, - renderTarget?D3DFMT_X8R8G8B8:D3DFMT_R5G6B5, + renderTarget?(useFloat?D3DFMT_A32B32G32R32F:D3DFMT_A8R8G8B8):D3DFMT_R5G6B5, renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, // render targets cannot be managed &tex, NULL ); @@ -534,7 +538,7 @@ void CD3DCG::Render(LPDIRECT3DTEXTURE9 &origTex, D3DXVECTOR2 textureSize, /* make sure the render target exists and has an appropriate size, then set as current render target with last pass as source */ - ensureTextureSize(shaderPasses[i].tex,shaderPasses[i].textureSize,D3DXVECTOR2(texSize,texSize),true); + ensureTextureSize(shaderPasses[i].tex,shaderPasses[i].textureSize,D3DXVECTOR2(texSize,texSize),true,shaderPasses[i].useFloatTex); shaderPasses[i].tex->GetSurfaceLevel(0,&pRenderSurface); pDevice->SetTexture(0, shaderPasses[i-1].tex); pDevice->SetRenderTarget(0,pRenderSurface); @@ -565,6 +569,8 @@ void CD3DCG::Render(LPDIRECT3DTEXTURE9 &origTex, D3DXVECTOR2 textureSize, */ setViewport(0,0,(DWORD)shaderPasses[i].outputSize.x,(DWORD)shaderPasses[i].outputSize.y); + pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + pDevice->BeginScene(); pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); pDevice->EndScene(); @@ -659,6 +665,7 @@ void CD3DCG::setShaderVars(int pass) #define setTextureParameter(pass,varname,val,linear)\ {\ CGparameter cgpf = cgGetNamedParameter(shaderPasses[pass].cgFragmentProgram, varname);\ + CGparameter cgpv = cgGetNamedParameter(shaderPasses[pass].cgVertexProgram, varname);\ if(cgpf) {\ cgD3D9SetTexture(cgpf,val);\ cgD3D9SetSamplerState(cgpf, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);\ @@ -666,6 +673,13 @@ void CD3DCG::setShaderVars(int pass) cgD3D9SetSamplerState(cgpf, D3DSAMP_MINFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);\ cgD3D9SetSamplerState(cgpf, D3DSAMP_MAGFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);\ }\ + if(cgpv) {\ + cgD3D9SetTexture(cgpv,val);\ + /*cgD3D9SetSamplerState(cgpv, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);\ + cgD3D9SetSamplerState(cgpv, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);\ + cgD3D9SetSamplerState(cgpv, D3DSAMP_MINFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);\ + cgD3D9SetSamplerState(cgpv, D3DSAMP_MAGFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);*/\ + }\ }\ #define setTexCoordsParameter(pass,varname,val)\ @@ -682,7 +696,10 @@ void CD3DCG::setShaderVars(int pass) setProgramUniform(pass,"IN.video_size",&inputSize); setProgramUniform(pass,"IN.texture_size",&textureSize); setProgramUniform(pass,"IN.output_size",&outputSize); - setProgramUniform(pass,"IN.frame_count",&frameCnt); + float shaderFrameCnt = frameCnt; + if(shaderPasses[pass].frameCounterMod) + shaderFrameCnt = (float)(frameCnt % shaderPasses[pass].frameCounterMod); + setProgramUniform(pass,"IN.frame_count",&shaderFrameCnt); float frameDirection = GUI.rewinding?-1.0f:1.0f; setProgramUniform(pass,"IN.frame_direction",&frameDirection); diff --git a/win32/CD3DCG.h b/win32/CD3DCG.h index f46d8aa6..ff3d7fab 100644 --- a/win32/CD3DCG.h +++ b/win32/CD3DCG.h @@ -197,6 +197,8 @@ private: typedef struct _shaderPass { cgScaleParams scaleParams; bool linearFilter; + bool useFloatTex; + unsigned int frameCounterMod; CGprogram cgVertexProgram, cgFragmentProgram; LPDIRECT3DTEXTURE9 tex; LPDIRECT3DVERTEXBUFFER9 vertexBuffer; @@ -240,14 +242,14 @@ private: void setVertexStream(IDirect3DVertexBuffer9 *vertexBuffer,D3DXVECTOR2 inputSize,D3DXVECTOR2 textureSize,D3DXVECTOR2 outputSize); void setViewport(DWORD x, DWORD y, DWORD width, DWORD height); void setShaderVars(int pass); - void ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, D3DXVECTOR2 wantedSize,bool renderTarget); + void ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, D3DXVECTOR2 wantedSize,bool renderTarget, bool useFloat = false); void fillParameterMap(std::vector &map, CGparameter param); void setupVertexDeclaration(shaderPass &pass); void calculateMatrix(); LPDIRECT3DDEVICE9 pDevice; CGcontext cgContext; - float frameCnt; + unsigned int frameCnt; D3DXMATRIX mvp; public: diff --git a/win32/CGLCG.cpp b/win32/CGLCG.cpp index 293f9ff2..0c5b5ab9 100644 --- a/win32/CGLCG.cpp +++ b/win32/CGLCG.cpp @@ -344,6 +344,10 @@ bool CGLCG::LoadShader(const TCHAR *shaderFile) pass.linearFilter = it->linearFilter; } + pass.frameCounterMod = it->frameCounterMod; + + pass.floatFbo = it->floatFbo; + // paths in the meta file can be relative _tfullpath(tempPath,_tFromChar(it->cgShaderFile),MAX_PATH); char *fileContents = ReadShaderFileContents(tempPath); @@ -405,7 +409,7 @@ bool CGLCG::LoadShader(const TCHAR *shaderFile) GLubyte *texData; if(loadPngImage(tempPath,width,height,hasAlpha,&texData)) { glPixelStorei(GL_UNPACK_ROW_LENGTH, width); - glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width, + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, texData); free(texData); } @@ -413,7 +417,7 @@ bool CGLCG::LoadShader(const TCHAR *shaderFile) STGA stga; if(loadTGA(tempPath,stga)) { glPixelStorei(GL_UNPACK_ROW_LENGTH, stga.width); - glTexImage2D(GL_TEXTURE_2D, 0, 4, stga.width, + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, stga.width, stga.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, stga.data); } } @@ -531,7 +535,7 @@ void CGLCG::Render(GLuint &origTex, xySize textureSize, xySize inputSize, xySize /* set size of output texture */ glBindTexture(GL_TEXTURE_2D,shaderPasses[i].tex); - glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,(unsigned int)shaderPasses[i].textureSize.x, + glTexImage2D(GL_TEXTURE_2D,0,(shaderPasses[i].floatFbo?GL_RGBA32F:GL_RGBA),(unsigned int)shaderPasses[i].textureSize.x, (unsigned int)shaderPasses[i].textureSize.y,0,GL_RGBA,GL_UNSIGNED_INT_8_8_8_8,NULL); /* viewport determines the area we render into the output texture @@ -666,7 +670,10 @@ void CGLCG::setShaderVars(int pass) setProgram2fv(pass,"IN.video_size",inputSize); setProgram2fv(pass,"IN.texture_size",textureSize); setProgram2fv(pass,"IN.output_size",outputSize); - setProgram1f(pass,"IN.frame_count",(float)frameCnt); + unsigned int shaderFrameCnt = frameCnt; + if(shaderPasses[pass].frameCounterMod) + shaderFrameCnt %= shaderPasses[pass].frameCounterMod; + setProgram1f(pass,"IN.frame_count",(float)shaderFrameCnt); setProgram1f(pass,"IN.frame_direction",GUI.rewinding?-1.0f:1.0f); /* ORIG parameter diff --git a/win32/CGLCG.h b/win32/CGLCG.h index c4a9ae0f..1c586936 100644 --- a/win32/CGLCG.h +++ b/win32/CGLCG.h @@ -212,6 +212,8 @@ private: typedef struct _shaderPass { cgScaleParams scaleParams; bool linearFilter; + unsigned frameCounterMod; + bool floatFbo; CGprogram cgVertexProgram, cgFragmentProgram; GLuint tex; GLuint fbo; @@ -256,7 +258,7 @@ private: bool loadTGA(const TCHAR *filename, STGA& tgaFile); CGcontext cgContext; - int frameCnt; + unsigned int frameCnt; static const GLfloat lut_coords[8]; diff --git a/win32/CXAudio2.cpp b/win32/CXAudio2.cpp index 90286f1b..712f71eb 100644 --- a/win32/CXAudio2.cpp +++ b/win32/CXAudio2.cpp @@ -390,10 +390,8 @@ void CXAudio2::ProcessSound() BYTE * curBuffer; UINT32 availableSamples; - UINT32 availableBytes; availableSamples = S9xGetSampleCount(); - availableBytes = availableSamples * (Settings.SixteenBitSound ? 2 : 1); while(availableSamples > singleBufferSamples && bufferCount < blockCount) { curBuffer = soundBuffer + writeOffset; @@ -401,5 +399,6 @@ void CXAudio2::ProcessSound() PushBuffer(singleBufferBytes,curBuffer,NULL); writeOffset+=singleBufferBytes; writeOffset%=sum_bufferSize; + availableSamples -= singleBufferSamples; } } diff --git a/win32/render.cpp b/win32/render.cpp index c7ade059..562f0b8e 100644 --- a/win32/render.cpp +++ b/win32/render.cpp @@ -494,7 +494,7 @@ void InitRenderFilters(void) #define Mask_3 0xF800 // 11111 000000 00000 #define CONVERT_16_TO_32(pixel) \ (((((pixel) >> 11) ) << /*RedShift+3*/ 19) | \ - ((((pixel) >> 6) & 0x1f) << /*GreenShift+3*/11) | \ + ((((pixel) >> 5) & 0x3f) << /*GreenShift+2*/10) | \ (((pixel) & 0x1f) << /*BlueShift+3*/ 3)) #define NUMBITS (16) #else diff --git a/win32/rsrc/resource.h b/win32/rsrc/resource.h index 34c4d5f2..f1c1e88f 100644 --- a/win32/rsrc/resource.h +++ b/win32/rsrc/resource.h @@ -442,15 +442,17 @@ #define ID_SOUND_22050HZ 40035 #define ID_SOUND_44100HZ 40036 #define ID_SOUND_30000HZ 40037 -#define ID_FILE_SAVE1 40045 -#define ID_FILE_SAVE2 40046 -#define ID_FILE_SAVE3 40047 -#define ID_FILE_SAVE4 40048 -#define ID_FILE_SAVE5 40049 -#define ID_FILE_SAVE6 40050 -#define ID_FILE_SAVE7 40051 -#define ID_FILE_SAVE8 40052 -#define ID_FILE_SAVE9 40053 +#define ID_FILE_SAVE0 40043 +#define ID_FILE_SAVE1 40044 +#define ID_FILE_SAVE2 40045 +#define ID_FILE_SAVE3 40046 +#define ID_FILE_SAVE4 40047 +#define ID_FILE_SAVE5 40048 +#define ID_FILE_SAVE6 40049 +#define ID_FILE_SAVE7 40050 +#define ID_FILE_SAVE8 40051 +#define ID_FILE_SAVE9 40052 +#define ID_FILE_LOAD0 40053 #define ID_FILE_LOAD1 40054 #define ID_FILE_LOAD2 40055 #define ID_FILE_LOAD3 40056 diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index 57b20e7a..25ebc5d8 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -972,6 +972,7 @@ BEGIN END POPUP "&Save Game Position" BEGIN + MENUITEM "Slot #&0", ID_FILE_SAVE0 MENUITEM "Slot #&1", ID_FILE_SAVE1 MENUITEM "Slot #&2", ID_FILE_SAVE2 MENUITEM "Slot #&3", ID_FILE_SAVE3 @@ -984,6 +985,7 @@ BEGIN END POPUP "&Load Game Position" BEGIN + MENUITEM "Slot #&0", ID_FILE_LOAD0 MENUITEM "Slot #&1", ID_FILE_LOAD1 MENUITEM "Slot #&2", ID_FILE_LOAD2 MENUITEM "Slot #&3", ID_FILE_LOAD3 diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp index a2a2e211..955d9f89 100644 --- a/win32/wconfig.cpp +++ b/win32/wconfig.cpp @@ -268,11 +268,6 @@ void WinSetDefaultValues () // CPU options Settings.Paused = false; - // ROM image and peripheral options - Settings.MultiPlayer5Master = false; - Settings.SuperScopeMaster = false; - Settings.MouseMaster = false; - #ifdef NETPLAY_SUPPORT Settings.Port = 1996; NetPlay.MaxFrameSkip = 10; @@ -298,8 +293,6 @@ static bool try_save(const char *fname, ConfigFile &conf){ return false; } -static char rom_filename [MAX_PATH] = {0}; - static bool S9xSaveConfigFile(ConfigFile &conf){ configMutex = CreateMutex(NULL, FALSE, TEXT("Snes9xConfigMutex")); @@ -349,18 +342,30 @@ static inline char *SkipSpaces (char *p) return (p); } -const char* WinParseCommandLineAndLoadConfigFile (char *line) +const TCHAR* WinParseCommandLineAndLoadConfigFile (TCHAR *line) { // Break the command line up into an array of string pointers, each pointer // points at a separate word or character sequence enclosed in quotes. + int count = 0; + static TCHAR return_filename[MAX_PATH]; + +#ifdef UNICODE + // split params into argv + TCHAR **params = CommandLineToArgvW(line, &count); + + // convert all parameters to utf8 + char **parameters = new char*[count]; + for(int i = 0; i < count; i++) { + int requiredChars = WideCharToMultiByte(CP_UTF8, 0, params[i], -1, NULL, 0, NULL, NULL); + parameters[i] = new char[requiredChars]; + WideCharToMultiByte(CP_UTF8, 0, params[i], -1, parameters[i], requiredChars, NULL, NULL); + } + LocalFree(params); +#else #define MAX_PARAMETERS 100 char *p = line; - static char *parameters [MAX_PARAMETERS]; - int count = 0; - - //parameters [count++] = "Snes9X"; - + char *parameters[MAX_PARAMETERS]; while (count < MAX_PARAMETERS && *p) { p = SkipSpaces (p); @@ -392,6 +397,7 @@ const char* WinParseCommandLineAndLoadConfigFile (char *line) } } +#endif configMutex = CreateMutex(NULL, FALSE, TEXT("Snes9xConfigMutex")); int times = 0; DWORD waitVal = WAIT_TIMEOUT; @@ -432,12 +438,19 @@ const char* WinParseCommandLineAndLoadConfigFile (char *line) CloseHandle(configMutex); const char* rf = S9xParseArgs (parameters, count); - /*if(rf) - strcpy(rom_filename, rf); - else - rom_filename[0] = '\0';*/ - return rf; + if(rf) // save rom_filename as TCHAR if available + lstrcpy(return_filename, _tFromChar(rf)); + +#ifdef UNICODE + // free parameters + for(int i = 0; i < count; i++) { + delete [] parameters[i]; + } + delete [] parameters; +#endif + + return rf ? return_filename : NULL; } #define S(x) GAMEDEVICE_VK_##x @@ -960,7 +973,6 @@ void WinRegisterConfigItems() AddBoolC("Cheat", Settings.ApplyCheats, true, "true to allow enabled cheats to be applied"); AddInvBoolC("Patch", Settings.NoPatch, true, "true to allow IPS/UPS patches to be applied (\"soft patching\")"); AddBoolC("BS", Settings.BS, false, "Broadcast Satellaview emulation"); - AddStringC("Filename", rom_filename, MAX_PATH, "", "filename of ROM to run when Snes9x opens"); #undef CATEGORY #ifdef NETPLAY_SUPPORT #define CATEGORY "Netplay" diff --git a/win32/win32.cpp b/win32/win32.cpp index db4eedfb..454f87f4 100644 --- a/win32/win32.cpp +++ b/win32/win32.cpp @@ -980,6 +980,13 @@ void S9xWinScanJoypads () #endif } +void S9xDetectJoypads() +{ + for (int C = 0; C != 16; C ++) + Joystick[C].Attached = joyGetDevCaps (JOYSTICKID1+C, &Joystick[C].Caps, + sizeof( JOYCAPS)) == JOYERR_NOERROR; +} + void InitSnes9X( void) { #ifdef DEBUGGER @@ -1023,9 +1030,7 @@ void InitSnes9X( void) S9xMovieInit (); - for (int C = 0; C != 16; C ++) - Joystick[C].Attached = joyGetDevCaps (JOYSTICKID1+C, &Joystick[C].Caps, - sizeof( JOYCAPS)) == JOYERR_NOERROR; + S9xDetectJoypads(); } void DeinitS9x() { diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index 7d641da2..764cc6f4 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -292,9 +292,10 @@ std::vector LuaScriptHWnds; VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); +void S9xDetectJoypads(); + extern HWND RamSearchHWnd; extern LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - #define NOTKNOWN "Unknown Company " #define HEADER_SIZE 512 #define INFO_LEN (0xFF - 0xC0) @@ -646,7 +647,7 @@ bool8 S9xLoadROMImage (const TCHAR *string); static void EnableServer (bool8 enable); #endif void WinDeleteRecentGamesList (); -const char* WinParseCommandLineAndLoadConfigFile (char *line); +const TCHAR* WinParseCommandLineAndLoadConfigFile (TCHAR *line); void WinRegisterConfigItems (); void WinSaveConfigFile (); void WinSetDefaultValues (); @@ -741,64 +742,47 @@ void ChangeInputDevice(void) Settings.SuperScopeMaster = false; Settings.MultiPlayer5Master = false; - CheckMenuItem(GUI.hMenu, IDM_ENABLE_MULTITAP, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_JUSTIFIER, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_MOUSE_TOGGLE, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_SCOPE_TOGGLE, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_MOUSE_SWAPPED, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_JUSTIFIERS, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_MULTITAP8, MFS_UNCHECKED); - CheckMenuItem(GUI.hMenu, IDM_SNES_JOYPAD, MFS_UNCHECKED); - switch(GUI.ControllerOption) { case SNES_MOUSE: Settings.MouseMaster = true; S9xSetController(0, CTL_MOUSE, 0, 0, 0, 0); S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_MOUSE_TOGGLE, MFS_CHECKED); break; case SNES_MOUSE_SWAPPED: Settings.MouseMaster = true; S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_MOUSE, 1, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_MOUSE_SWAPPED, MFS_CHECKED); break; case SNES_SUPERSCOPE: Settings.SuperScopeMaster = true; S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_SCOPE_TOGGLE, MFS_CHECKED); break; case SNES_MULTIPLAYER5: Settings.MultiPlayer5Master = true; S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_MP5, 1, 2, 3, 4); - CheckMenuItem(GUI.hMenu, IDM_ENABLE_MULTITAP, MFS_CHECKED); break; case SNES_MULTIPLAYER8: Settings.MultiPlayer5Master = true; S9xSetController(0, CTL_MP5, 0, 1, 2, 3); S9xSetController(1, CTL_MP5, 4, 5, 6, 7); - CheckMenuItem(GUI.hMenu, IDM_ENABLE_MULTITAP, MFS_CHECKED); break; case SNES_JUSTIFIER: Settings.JustifierMaster = true; S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_JUSTIFIER, 0, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_JUSTIFIER, MFS_CHECKED); break; case SNES_JUSTIFIER_2: Settings.JustifierMaster = true; S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_JUSTIFIER, 1, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_JUSTIFIERS, MFS_CHECKED); break; default: case SNES_JOYPAD: S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0); - CheckMenuItem(GUI.hMenu, IDM_SNES_JOYPAD, MFS_CHECKED); break; } @@ -2361,60 +2345,66 @@ LRESULT CALLBACK WinProc( Settings.FrameAdvance = false; GUI.FrameAdvanceJustPressed = 0; break; - case ID_FILE_LOAD1: + case ID_FILE_LOAD0: FreezeUnfreeze (0, FALSE); break; - case ID_FILE_LOAD2: + case ID_FILE_LOAD1: FreezeUnfreeze (1, FALSE); break; - case ID_FILE_LOAD3: + case ID_FILE_LOAD2: FreezeUnfreeze (2, FALSE); break; - case ID_FILE_LOAD4: + case ID_FILE_LOAD3: FreezeUnfreeze (3, FALSE); break; - case ID_FILE_LOAD5: + case ID_FILE_LOAD4: FreezeUnfreeze (4, FALSE); break; - case ID_FILE_LOAD6: + case ID_FILE_LOAD5: FreezeUnfreeze (5, FALSE); break; - case ID_FILE_LOAD7: + case ID_FILE_LOAD6: FreezeUnfreeze (6, FALSE); break; - case ID_FILE_LOAD8: + case ID_FILE_LOAD7: FreezeUnfreeze (7, FALSE); break; - case ID_FILE_LOAD9: + case ID_FILE_LOAD8: FreezeUnfreeze (8, FALSE); break; - case ID_FILE_SAVE1: - FreezeUnfreeze (0, TRUE); + case ID_FILE_LOAD9: + FreezeUnfreeze (9, FALSE); break; - case ID_FILE_SAVE2: + case ID_FILE_SAVE0: + FreezeUnfreeze (0, TRUE); + break; + case ID_FILE_SAVE1: FreezeUnfreeze (1, TRUE); break; - case ID_FILE_SAVE3: + case ID_FILE_SAVE2: FreezeUnfreeze (2, TRUE); break; - case ID_FILE_SAVE4: + case ID_FILE_SAVE3: FreezeUnfreeze (3, TRUE); break; - case ID_FILE_SAVE5: + case ID_FILE_SAVE4: FreezeUnfreeze (4, TRUE); break; - case ID_FILE_SAVE6: + case ID_FILE_SAVE5: FreezeUnfreeze (5, TRUE); break; - case ID_FILE_SAVE7: + case ID_FILE_SAVE6: FreezeUnfreeze (6, TRUE); break; - case ID_FILE_SAVE8: + case ID_FILE_SAVE7: FreezeUnfreeze (7, TRUE); break; - case ID_FILE_SAVE9: + case ID_FILE_SAVE8: FreezeUnfreeze (8, TRUE); break; + case ID_FILE_SAVE9: + FreezeUnfreeze (9, TRUE); + break; case ID_CHEAT_ENTER: RestoreGUIDisplay (); DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEATER), hWnd, DlgCheater); @@ -2724,6 +2714,9 @@ LRESULT CALLBACK WinProc( #endif break; #endif + case WM_DEVICECHANGE: + S9xDetectJoypads(); + break; } return DefWindowProc (hWnd, uMsg, wParam, lParam); } @@ -3396,7 +3389,6 @@ int WINAPI WinMain( LPSTR lpCmdLine, int nCmdShow) { - char cmdLine[MAX_PATH]; Settings.StopEmulation = TRUE; SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR)); @@ -3416,8 +3408,9 @@ int WINAPI WinMain( ConfigFile::SetAlphaSort(false); ConfigFile::SetTimeSort(false); - strcpy(cmdLine,_tToChar(GetCommandLine())); - const char *rom_filename = WinParseCommandLineAndLoadConfigFile (cmdLine); + ChangeInputDevice(); + + const TCHAR *rom_filename = WinParseCommandLineAndLoadConfigFile (GetCommandLine()); WinSaveConfigFile (); WinLockConfigFile (); @@ -3486,11 +3479,10 @@ int WINAPI WinMain( } if(rom_filename) - LoadROM(_tFromChar(rom_filename)); + LoadROM(rom_filename); S9xUnmapAllControls(); S9xSetupDefaultKeymap(); - ChangeInputDevice(); DWORD lastTime = timeGetTime(); @@ -10620,8 +10612,10 @@ void S9xPostRomInit() if(!S9xMovieActive() && !startingMovie) { // revert previously forced control - if(GUI.ControlForced!=0xff) + if(GUI.ControlForced!=0xff) { GUI.ControllerOption = GUI.ControlForced; + ChangeInputDevice(); + } int prevController = GUI.ControllerOption; GUI.ValidControllerOptions = 0xFFFF; @@ -10704,10 +10698,10 @@ void S9xPostRomInit() GUI.ValidControllerOptions = (1<