Update to v083r10 release.

byuu says:

Changelog:
- NES: added VRC1, VRC2, VRC3, MMC6 emulation
- shrink window doesn't do anything when no cartridge is loaded
- phoenix Horizontal,VerticalLayout use const Size& instead of unsigned
  width,height [for consistency]

So, all official NES ASICs are supported now. Just need sound output for
MMC5+VRC7 to complete them; and then some board re-arrangement stuff for
VRC2+MMC3.

Note that MMC6 uses the same mapper ID as MMC3, and VRC2 uses the same
ID as VRC4, so you have to make a BML board mapping or toggle which type
is chosen in the source file to use these two chips.

Side note: NES overscan clamping is obviously still assuming 16-bit, as
only half the lines are erased. Need to fix that.
This commit is contained in:
Tim Allen 2011-11-04 22:57:54 +11:00
parent bf78e66027
commit 891f1ab7af
51 changed files with 1102 additions and 270 deletions

View File

@ -7,9 +7,11 @@
namespace nall { namespace nall {
template<typename T> struct reference_array { template<typename T> struct reference_array {
struct exception_out_of_bounds{};
protected: protected:
typedef typename std::remove_reference<T>::type *Tptr; typedef typename std::remove_reference<T>::type type_t;
Tptr *pool; type_t **pool;
unsigned poolsize, buffersize; unsigned poolsize, buffersize;
public: public:
@ -26,7 +28,7 @@ namespace nall {
void reserve(unsigned newsize) { void reserve(unsigned newsize) {
if(newsize == poolsize) return; if(newsize == poolsize) return;
pool = (Tptr*)realloc(pool, newsize * sizeof(T)); pool = (type_t**)realloc(pool, sizeof(type_t*) * newsize);
poolsize = newsize; poolsize = newsize;
buffersize = min(buffersize, newsize); buffersize = min(buffersize, newsize);
} }
@ -37,13 +39,13 @@ namespace nall {
} }
template<typename... Args> template<typename... Args>
bool append(const T& data, Args&&... args) { bool append(type_t& data, Args&&... args) {
bool result = append(data); bool result = append(data);
append(std::forward<Args>(args)...); append(std::forward<Args>(args)...);
return result; return result;
} }
bool append(const T data) { bool append(type_t& data) {
for(unsigned index = 0; index < buffersize; index++) { for(unsigned index = 0; index < buffersize; index++) {
if(pool[index] == &data) return false; if(pool[index] == &data) return false;
} }
@ -54,7 +56,7 @@ namespace nall {
return true; return true;
} }
bool remove(const T data) { bool remove(type_t& data) {
for(unsigned index = 0; index < buffersize; index++) { for(unsigned index = 0; index < buffersize; index++) {
if(pool[index] == &data) { if(pool[index] == &data) {
for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1]; for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1];
@ -77,8 +79,8 @@ namespace nall {
if(pool) free(pool); if(pool) free(pool);
buffersize = source.buffersize; buffersize = source.buffersize;
poolsize = source.poolsize; poolsize = source.poolsize;
pool = (Tptr*)malloc(sizeof(T) * poolsize); pool = (type_t**)malloc(sizeof(type_t*) * poolsize);
memcpy(pool, source.pool, sizeof(T) * buffersize); memcpy(pool, source.pool, sizeof(type_t*) * buffersize);
return *this; return *this;
} }
@ -92,20 +94,20 @@ namespace nall {
return *this; return *this;
} }
inline T operator[](unsigned index) { inline type_t& operator[](unsigned index) {
if(index >= buffersize) throw "reference_array[] out of bounds"; if(index >= buffersize) throw exception_out_of_bounds();
return *pool[index]; return *pool[index];
} }
inline const T operator[](unsigned index) const { inline type_t& operator[](unsigned index) const {
if(index >= buffersize) throw "reference_array[] out of bounds"; if(index >= buffersize) throw exception_out_of_bounds();
return *pool[index]; return *pool[index];
} }
//iteration //iteration
struct iterator { struct iterator {
bool operator!=(const iterator &source) const { return index != source.index; } bool operator!=(const iterator &source) const { return index != source.index; }
T& operator*() { return array.operator[](index); } type_t& operator*() { return array.operator[](index); }
iterator& operator++() { index++; return *this; } iterator& operator++() { index++; return *this; }
iterator(const reference_array &array, unsigned index) : array(array), index(index) {} iterator(const reference_array &array, unsigned index) : array(array), index(index) {}
private: private:

View File

@ -1,4 +1,7 @@
#include "bandai-fcg.cpp" #include "bandai-fcg.cpp"
#include "konami-vrc1.cpp"
#include "konami-vrc2.cpp"
#include "konami-vrc3.cpp"
#include "konami-vrc4.cpp" #include "konami-vrc4.cpp"
#include "konami-vrc6.cpp" #include "konami-vrc6.cpp"
#include "konami-vrc7.cpp" #include "konami-vrc7.cpp"
@ -8,6 +11,7 @@
#include "nes-exrom.cpp" #include "nes-exrom.cpp"
#include "nes-fxrom.cpp" #include "nes-fxrom.cpp"
#include "nes-gxrom.cpp" #include "nes-gxrom.cpp"
#include "nes-hkrom.cpp"
#include "nes-nrom.cpp" #include "nes-nrom.cpp"
#include "nes-pxrom.cpp" #include "nes-pxrom.cpp"
#include "nes-sxrom.cpp" #include "nes-sxrom.cpp"
@ -113,6 +117,9 @@ Board* Board::load(const string &markup, const uint8_t *data, unsigned size) {
if(type == "BANDAI-FCG") return new BandaiFCG(board, data, size); if(type == "BANDAI-FCG") return new BandaiFCG(board, data, size);
if(type == "KONAMI-VRC-1") return new KonamiVRC1(board, data, size);
if(type == "KONAMI-VRC-2") return new KonamiVRC2(board, data, size);
if(type == "KONAMI-VRC-3") return new KonamiVRC3(board, data, size);
if(type == "KONAMI-VRC-4") return new KonamiVRC4(board, data, size); if(type == "KONAMI-VRC-4") return new KonamiVRC4(board, data, size);
if(type == "KONAMI-VRC-6") return new KonamiVRC6(board, data, size); if(type == "KONAMI-VRC-6") return new KonamiVRC6(board, data, size);
if(type == "KONAMI-VRC-7") return new KonamiVRC7(board, data, size); if(type == "KONAMI-VRC-7") return new KonamiVRC7(board, data, size);
@ -137,6 +144,8 @@ Board* Board::load(const string &markup, const uint8_t *data, unsigned size) {
if(type == "NES-GNROM" ) return new NES_GxROM(board, data, size); if(type == "NES-GNROM" ) return new NES_GxROM(board, data, size);
if(type == "NES-MHROM" ) return new NES_GxROM(board, data, size); if(type == "NES-MHROM" ) return new NES_GxROM(board, data, size);
if(type == "NES-HKROM" ) return new NES_HKROM(board, data, size);
if(type == "NES-NROM-128") return new NES_NROM(board, data, size); if(type == "NES-NROM-128") return new NES_NROM(board, data, size);
if(type == "NES-NROM-256") return new NES_NROM(board, data, size); if(type == "NES-NROM-256") return new NES_NROM(board, data, size);

View File

@ -0,0 +1,40 @@
struct KonamiVRC1 : Board {
VRC1 vrc1;
uint8 prg_read(unsigned addr) {
if(addr & 0x8000) return prgrom.read(vrc1.prg_addr(addr));
return cpu.mdr();
}
void prg_write(unsigned addr, uint8 data) {
if(addr & 0x8000) return vrc1.reg_write(addr, data);
}
uint8 chr_read(unsigned addr) {
if(addr & 0x2000) return ppu.ciram_read(vrc1.ciram_addr(addr));
return Board::chr_read(vrc1.chr_addr(addr));
}
void chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) return ppu.ciram_write(vrc1.ciram_addr(addr), data);
return Board::chr_write(vrc1.chr_addr(addr), data);
}
void power() {
vrc1.power();
}
void reset() {
vrc1.reset();
}
void serialize(serializer &s) {
Board::serialize(s);
vrc1.serialize(s);
}
KonamiVRC1(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc1(*this) {
}
};

View File

@ -0,0 +1,45 @@
struct KonamiVRC2 : Board {
VRC2 vrc2;
bool latch;
uint8 prg_read(unsigned addr) {
if(addr == 0x6000) return latch;
if(addr & 0x8000) return prgrom.read(vrc2.prg_addr(addr));
return cpu.mdr();
}
void prg_write(unsigned addr, uint8 data) {
if(addr == 0x6000) latch = data & 0x01;
if(addr & 0x8000) return vrc2.reg_write(addr, data);
}
uint8 chr_read(unsigned addr) {
if(addr & 0x2000) return ppu.ciram_read(vrc2.ciram_addr(addr));
return Board::chr_read(vrc2.chr_addr(addr));
}
void chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) return ppu.ciram_write(vrc2.ciram_addr(addr), data);
return Board::chr_write(vrc2.chr_addr(addr), data);
}
void power() {
vrc2.power();
}
void reset() {
vrc2.reset();
latch = 0;
}
void serialize(serializer &s) {
Board::serialize(s);
vrc2.serialize(s);
s.integer(latch);
}
KonamiVRC2(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) {
}
};

View File

@ -0,0 +1,57 @@
struct KonamiVRC3 : Board {
struct Settings {
bool mirror; //0 = horizontal, 1 = vertical
} settings;
VRC3 vrc3;
void main() {
vrc3.main();
}
uint8 prg_read(unsigned addr) {
if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff);
if(addr & 0x8000) return prgrom.read(vrc3.prg_addr(addr));
return cpu.mdr();
}
void prg_write(unsigned addr, uint8 data) {
if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data);
if(addr & 0x8000) return vrc3.reg_write(addr, data);
}
uint8 chr_read(unsigned addr) {
if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_read(addr & 0x07ff);
}
return chrram.read(addr);
}
void chr_write(unsigned addr, uint8 data) {
if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.ciram_write(addr & 0x07ff, data);
}
return chrram.write(addr, data);
}
void power() {
vrc3.power();
}
void reset() {
vrc3.reset();
}
void serialize(serializer &s) {
Board::serialize(s);
vrc3.serialize(s);
}
KonamiVRC3(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc3(*this) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
}
};

View File

@ -0,0 +1,48 @@
struct NES_HKROM : Board {
MMC6 mmc6;
void main() {
mmc6.main();
}
uint8 prg_read(unsigned addr) {
if((addr & 0xf000) == 0x7000) return mmc6.ram_read(addr);
if(addr & 0x8000) return prgrom.read(mmc6.prg_addr(addr));
return cpu.mdr();
}
void prg_write(unsigned addr, uint8 data) {
if((addr & 0xf000) == 0x7000) return mmc6.ram_write(addr, data);
if(addr & 0x8000) return mmc6.reg_write(addr, data);
}
uint8 chr_read(unsigned addr) {
mmc6.irq_test(addr);
if(addr & 0x2000) return ppu.ciram_read(mmc6.ciram_addr(addr));
return Board::chr_read(mmc6.chr_addr(addr));
}
void chr_write(unsigned addr, uint8 data) {
mmc6.irq_test(addr);
if(addr & 0x2000) return ppu.ciram_write(mmc6.ciram_addr(addr), data);
return Board::chr_write(mmc6.chr_addr(addr), data);
}
void power() {
mmc6.power();
}
void reset() {
mmc6.reset();
}
void serialize(serializer &s) {
Board::serialize(s);
mmc6.serialize(s);
}
NES_HKROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc6(*this) {
}
};

View File

@ -32,53 +32,7 @@ uint8 prg_read(unsigned addr) {
void prg_write(unsigned addr, uint8 data) { void prg_write(unsigned addr, uint8 data) {
if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data); if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data);
if(addr & 0x8000) return mmc3.reg_write(addr, data);
switch(addr & 0xe001) {
case 0x8000:
mmc3.chr_mode = data & 0x80;
mmc3.prg_mode = data & 0x40;
mmc3.bank_select = data & 0x07;
break;
case 0x8001:
switch(mmc3.bank_select) {
case 0: mmc3.chr_bank[0] = data & ~1; break;
case 1: mmc3.chr_bank[1] = data & ~1; break;
case 2: mmc3.chr_bank[2] = data; break;
case 3: mmc3.chr_bank[3] = data; break;
case 4: mmc3.chr_bank[4] = data; break;
case 5: mmc3.chr_bank[5] = data; break;
case 6: mmc3.prg_bank[0] = data & 0x3f; break;
case 7: mmc3.prg_bank[1] = data & 0x3f; break;
}
break;
case 0xa000:
mmc3.mirror = data & 0x01;
break;
case 0xa001:
mmc3.ram_enable = data & 0x80;
mmc3.ram_write_protect = data & 0x40;
break;
case 0xc000:
mmc3.irq_latch = data;
break;
case 0xc001:
mmc3.irq_counter = 0;
break;
case 0xe000:
mmc3.irq_enable = false;
mmc3.irq_line = 0;
break;
case 0xe001:
mmc3.irq_enable = true;
break;
}
} }
uint8 chr_read(unsigned addr) { uint8 chr_read(unsigned addr) {

View File

@ -1,6 +1,10 @@
#include "mmc1.cpp" #include "mmc1.cpp"
#include "mmc3.cpp" #include "mmc3.cpp"
#include "mmc5.cpp" #include "mmc5.cpp"
#include "mmc6.cpp"
#include "vrc1.cpp"
#include "vrc2.cpp"
#include "vrc3.cpp"
#include "vrc4.cpp" #include "vrc4.cpp"
#include "vrc6.cpp" #include "vrc6.cpp"
#include "vrc7.cpp" #include "vrc7.cpp"

View File

@ -89,6 +89,55 @@ void ram_write(unsigned addr, uint8 data) {
if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data; if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data;
} }
void reg_write(unsigned addr, uint8 data) {
switch(addr & 0xe001) {
case 0x8000:
chr_mode = data & 0x80;
prg_mode = data & 0x40;
bank_select = data & 0x07;
break;
case 0x8001:
switch(bank_select) {
case 0: chr_bank[0] = data & ~1; break;
case 1: chr_bank[1] = data & ~1; break;
case 2: chr_bank[2] = data; break;
case 3: chr_bank[3] = data; break;
case 4: chr_bank[4] = data; break;
case 5: chr_bank[5] = data; break;
case 6: prg_bank[0] = data & 0x3f; break;
case 7: prg_bank[1] = data & 0x3f; break;
}
break;
case 0xa000:
mirror = data & 0x01;
break;
case 0xa001:
ram_enable = data & 0x80;
ram_write_protect = data & 0x40;
break;
case 0xc000:
irq_latch = data;
break;
case 0xc001:
irq_counter = 0;
break;
case 0xe000:
irq_enable = false;
irq_line = 0;
break;
case 0xe001:
irq_enable = true;
break;
}
}
void power() { void power() {
} }

200
bsnes/nes/cartridge/chip/mmc6.cpp Executable file
View File

@ -0,0 +1,200 @@
struct MMC6 : Chip {
bool chr_mode;
bool prg_mode;
bool ram_enable;
uint3 bank_select;
uint8 prg_bank[2];
uint8 chr_bank[6];
bool mirror;
bool ram_readable[2];
bool ram_writable[2];
uint8 irq_latch;
uint8 irq_counter;
bool irq_enable;
unsigned irq_delay;
bool irq_line;
uint16 chr_abus;
void main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(irq_delay) irq_delay--;
cpu.set_irq_line(irq_line);
tick();
}
}
void irq_test(unsigned addr) {
if(!(chr_abus & 0x1000) && (addr & 0x1000)) {
if(irq_delay == 0) {
if(irq_counter == 0) {
irq_counter = irq_latch;
} else if(--irq_counter == 0) {
if(irq_enable) irq_line = 1;
}
}
irq_delay = 6;
}
chr_abus = addr;
}
unsigned prg_addr(unsigned addr) const {
switch((addr >> 13) & 3) {
case 0:
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff);
case 1:
return (prg_bank[1] << 13) | (addr & 0x1fff);
case 2:
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff);
case 3:
return (0x3f << 13) | (addr & 0x1fff);
}
}
unsigned chr_addr(unsigned addr) const {
if(chr_mode == 0) {
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
} else {
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
}
}
unsigned ciram_addr(unsigned addr) const {
if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
}
uint8 ram_read(unsigned addr) {
if(ram_enable == false) return cpu.mdr();
if(ram_readable[0] == false && ram_readable[1] == false) return cpu.mdr();
bool region = addr & 0x0200;
if(ram_readable[region] == false) return 0x00;
return board.prgram.read((region * 0x0200) + (addr & 0x01ff));
}
void ram_write(unsigned addr, uint8 data) {
if(ram_enable == false) return;
bool region = addr & 0x0200;
if(ram_writable[region] == false) return;
return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data);
}
void reg_write(unsigned addr, uint8 data) {
switch(addr & 0xe001) {
case 0x8000:
chr_mode = data & 0x80;
prg_mode = data & 0x40;
ram_enable = data & 0x20;
bank_select = data & 0x07;
if(ram_enable == false) {
for(auto &n : ram_readable) n = false;
for(auto &n : ram_writable) n = false;
}
break;
case 0x8001:
switch(bank_select) {
case 0: chr_bank[0] = data & ~1; break;
case 1: chr_bank[1] = data & ~1; break;
case 2: chr_bank[2] = data; break;
case 3: chr_bank[3] = data; break;
case 4: chr_bank[4] = data; break;
case 5: chr_bank[5] = data; break;
case 6: prg_bank[0] = data & 0x3f; break;
case 7: prg_bank[1] = data & 0x3f; break;
}
break;
case 0xa000:
mirror = data & 0x01;
break;
case 0xa001:
if(ram_enable == false) break;
ram_readable[1] = data & 0x80;
ram_writable[1] = data & 0x40;
ram_readable[0] = data & 0x20;
ram_writable[0] = data & 0x10;
break;
case 0xc000:
irq_latch = data;
break;
case 0xc001:
irq_counter = 0;
break;
case 0xe000:
irq_enable = false;
irq_line = 0;
break;
case 0xe001:
irq_enable = true;
break;
}
}
void power() {
}
void reset() {
chr_mode = 0;
prg_mode = 0;
ram_enable = 0;
bank_select = 0;
for(auto &n : prg_bank) n = 0;
for(auto &n : chr_bank) n = 0;
mirror = 0;
for(auto &n : ram_readable) n = 0;
for(auto &n : ram_writable) n = 0;
irq_latch = 0;
irq_counter = 0;
irq_enable = 0;
irq_delay = 0;
irq_line = 0;
chr_abus = 0;
}
void serialize(serializer &s) {
s.integer(chr_mode);
s.integer(prg_mode);
s.integer(ram_enable);
s.integer(bank_select);
for(auto &n : prg_bank) s.integer(n);
for(auto &n : chr_bank) s.integer(n);
s.integer(mirror);
for(auto &n : ram_readable) s.integer(n);
for(auto &n : ram_writable) s.integer(n);
s.integer(irq_latch);
s.integer(irq_counter);
s.integer(irq_enable);
s.integer(irq_delay);
s.integer(irq_line);
s.integer(chr_abus);
}
MMC6(Board &board) : Chip(board) {
}
};

View File

@ -0,0 +1,80 @@
struct VRC1 : Chip {
uint4 prg_bank[3];
uint4 chr_banklo[2];
bool chr_bankhi[2];
bool mirror;
unsigned prg_addr(unsigned addr) const {
unsigned bank = 0x0f;
if((addr & 0xe000) == 0x8000) bank = prg_bank[0];
if((addr & 0xe000) == 0xa000) bank = prg_bank[1];
if((addr & 0xe000) == 0xc000) bank = prg_bank[2];
return (bank * 0x2000) + (addr & 0x1fff);
}
unsigned chr_addr(unsigned addr) const {
unsigned bank = chr_banklo[(bool)(addr & 0x1000)];
bank |= chr_bankhi[(bool)(addr & 0x1000)] << 4;
return (bank * 0x1000) + (addr & 0x0fff);
}
unsigned ciram_addr(unsigned addr) const {
switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
}
throw;
}
void reg_write(unsigned addr, uint8 data) {
switch(addr & 0xf000) {
case 0x8000:
prg_bank[0] = data & 0x0f;
break;
case 0x9000:
chr_bankhi[1] = data & 0x04;
chr_bankhi[0] = data & 0x02;
mirror = data & 0x01;
break;
case 0xa000:
prg_bank[1] = data & 0x0f;
break;
case 0xc000:
prg_bank[2] = data & 0x0f;
break;
case 0xe000:
chr_banklo[0] = data & 0x0f;
break;
case 0xf000:
chr_banklo[1] = data & 0x0f;
break;
}
}
void power() {
}
void reset() {
for(auto &n : prg_bank) n = 0;
for(auto &n : chr_banklo) n = 0;
for(auto &n : chr_bankhi) n = 0;
mirror = 0;
}
void serialize(serializer &s) {
for(auto &n : prg_bank) s.integer(n);
for(auto &n : chr_banklo) s.integer(n);
for(auto &n : chr_bankhi) s.integer(n);
s.integer(mirror);
}
VRC1(Board &board) : Chip(board) {
}
};

View File

@ -0,0 +1,91 @@
struct VRC2 : Chip {
uint4 prg_bank[2];
uint8 chr_bank[8];
uint2 mirror;
unsigned prg_addr(unsigned addr) const {
unsigned bank;
switch(addr & 0xe000) {
case 0x8000: bank = prg_bank[0]; break;
case 0xa000: bank = prg_bank[1]; break;
case 0xc000: bank = 0x0e; break;
case 0xe000: bank = 0x0f; break;
}
return (bank * 0x2000) + (addr & 0x1fff);
}
unsigned chr_addr(unsigned addr) const {
unsigned bank = chr_bank[addr / 0x0400];
return (bank * 0x0400) + (addr & 0x03ff);
}
unsigned ciram_addr(unsigned addr) const {
switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
}
throw;
}
void reg_write(unsigned addr, uint8 data) {
switch(addr) {
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
prg_bank[0] = data & 0x0f;
break;
case 0x9000: case 0x9001: case 0x9002: case 0x9003:
mirror = data & 0x03;
break;
case 0xa000: case 0xa001: case 0xa002: case 0xa003:
prg_bank[1] = data & 0x0f;
break;
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break;
}
}
void power() {
}
void reset() {
for(auto &n : prg_bank) n = 0;
for(auto &n : chr_bank) n = 0;
mirror = 0;
}
void serialize(serializer &s) {
for(auto &n : prg_bank) s.integer(n);
for(auto &n : chr_bank) s.integer(n);
s.integer(mirror);
}
VRC2(Board &board) : Chip(board) {
}
};

100
bsnes/nes/cartridge/chip/vrc3.cpp Executable file
View File

@ -0,0 +1,100 @@
struct VRC3 : Chip {
uint4 prg_bank;
bool irq_mode;
bool irq_enable;
bool irq_acknowledge;
uint16 irq_latch;
struct {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
} irq_counter;
bool irq_line;
void main() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(irq_enable) {
if(irq_mode == 0) { //16-bit
if(++irq_counter.w == 0) {
irq_line = 1;
irq_enable = irq_acknowledge;
irq_counter.w = irq_latch;
}
}
if(irq_mode == 1) { //8-bit
if(++irq_counter.l == 0) {
irq_line = 1;
irq_enable = irq_acknowledge;
irq_counter.l = irq_latch;
}
}
}
cpu.set_irq_line(irq_line);
tick();
}
}
unsigned prg_addr(unsigned addr) const {
unsigned bank = (addr < 0xc000 ? (unsigned)prg_bank : 0x0f);
return (bank * 0x4000) + (addr & 0x3fff);
}
void reg_write(unsigned addr, uint8 data) {
switch(addr & 0xf000) {
case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) << 0); break;
case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) << 4); break;
case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) << 8); break;
case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break;
case 0xc000:
irq_mode = data & 0x04;
irq_enable = data & 0x02;
irq_acknowledge = data & 0x01;
if(irq_enable) irq_counter.w = irq_latch;
break;
case 0xd000:
irq_line = 0;
irq_enable = irq_acknowledge;
break;
case 0xf000:
prg_bank = data & 0x0f;
break;
}
}
void power() {
}
void reset() {
prg_bank = 0;
irq_mode = 0;
irq_enable = 0;
irq_acknowledge = 0;
irq_latch = 0;
irq_counter.w = 0;
irq_line = 0;
}
void serialize(serializer &s) {
s.integer(prg_bank);
s.integer(irq_mode);
s.integer(irq_enable);
s.integer(irq_acknowledge);
s.integer(irq_latch);
s.integer(irq_counter.w);
s.integer(irq_line);
}
VRC3(Board &board) : Chip(board) {
}
};

View File

@ -140,6 +140,7 @@ unsigned ciram_addr(unsigned addr) const {
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
} }
throw;
} }
void power() { void power() {

View File

@ -14,7 +14,7 @@ static string iNES(const uint8_t *data, unsigned size) {
unsigned prgram = 0; unsigned prgram = 0;
unsigned chrram = chrrom == 0 ? 8192 : 0; unsigned chrram = chrrom == 0 ? 8192 : 0;
//print("iNES mapper: ", mapper, "\n"); print("iNES mapper: ", mapper, "\n");
output.append("cartridge\n"); output.append("cartridge\n");
@ -41,9 +41,14 @@ static string iNES(const uint8_t *data, unsigned size) {
break; break;
case 4: case 4:
//MMC3
output.append("\tboard type:NES-TLROM\n"); output.append("\tboard type:NES-TLROM\n");
output.append("\t\tchip type:MMC3B\n"); output.append("\t\tchip type:MMC3B\n");
prgram = 8192; prgram = 8192;
//MMC6
//output.append("\tboard type:NES-HKROM\n");
//output.append("\t\tchip type:MMC6\n");
//prgram = 1024;
break; break;
case 5: case 5:
@ -76,6 +81,10 @@ static string iNES(const uint8_t *data, unsigned size) {
case 21: case 21:
case 23: case 23:
case 25: case 25:
//VRC2
//output.append("\tboard type:KONAMI-VRC-2\n");
//output.append("\t\tchip type:VRC2\n");
//VRC4
output.append("\tboard type:KONAMI-VRC-4\n"); output.append("\tboard type:KONAMI-VRC-4\n");
output.append("\t\tchip type:VRC4\n"); output.append("\t\tchip type:VRC4\n");
output.append("\t\t\tpinout a0=1 a1=0\n"); output.append("\t\t\tpinout a0=1 a1=0\n");
@ -109,6 +118,18 @@ static string iNES(const uint8_t *data, unsigned size) {
prgram = 8192; prgram = 8192;
break; break;
case 73:
output.append("\tboard type:KONAMI-VRC-3\n");
output.append("\t\tchip type:VRC3\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
prgram = 8192;
break;
case 75:
output.append("\tboard type:KONAMI-VRC-1\n");
output.append("\t\tchip type:VRC1\n");
break;
case 85: case 85:
output.append("\tboard type:KONAMI-VRC-7\n"); output.append("\tboard type:KONAMI-VRC-7\n");
output.append("\t\tchip type:VRC7\n"); output.append("\t\tchip type:VRC7\n");
@ -119,7 +140,7 @@ static string iNES(const uint8_t *data, unsigned size) {
output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n"); output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n");
output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n"); output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n");
//print(output, "\n"); print(output, "\n");
return output; return output;
} }

View File

@ -162,6 +162,7 @@ string CPU::disassemble() {
op(0xe6, inc, zpg); op(0xe6, inc, zpg);
op(0xe8, inx, imp); op(0xe8, inx, imp);
op(0xe9, sbc, imm); op(0xe9, sbc, imm);
op(0xea, nop, imp);
op(0xec, cpx, abs); op(0xec, cpx, abs);
op(0xed, sbc, abs); op(0xed, sbc, abs);
op(0xee, inc, abs); op(0xee, inc, abs);

View File

@ -27,6 +27,85 @@ Font::Font(const string &description):
description(description) { description(description) {
} }
//Image
//=====
bool Image::load(const string &filename, const Color &alpha) {
if(data) { delete[] data; data = nullptr; }
file fp;
if(fp.open(filename, file::mode::read) == false) return false;
uint8_t d0 = fp.read();
uint8_t d1 = fp.read();
uint8_t d2 = fp.read();
uint8_t d3 = fp.read();
fp.close();
if(d0 == 'B' && d1 == 'M') {
bmp::read(filename, data, width, height);
}
if(d0 == 0x89 && d1 == 'P' && d2 == 'N' && d3 == 'G') {
png image;
if(image.decode(filename)) {
image.alphaTransform((alpha.red << 16) + (alpha.green << 8) + (alpha.blue << 0));
width = image.info.width, height = image.info.height;
data = new uint32_t[width * height];
memcpy(data, image.data, width * height * sizeof(uint32_t));
}
}
return data;
}
void Image::load(const uint32_t *data, const Size &size) {
if(data) { delete[] data; data = nullptr; }
width = size.width, height = size.height;
this->data = new uint32_t[width * height];
memcpy(this->data, data, width * height * sizeof(uint32_t));
}
Image& Image::operator=(const Image &source) {
if(this == &source) return *this;
if(data) { delete[] data; data = nullptr; }
if(source.data == nullptr) return *this;
width = source.width, height = source.height;
data = new uint32_t[width * height];
memcpy(data, source.data, width * height * sizeof(uint32_t));
return *this;
}
Image& Image::operator=(Image &&source) {
if(this == &source) return *this;
if(data) { delete[] data; data = nullptr; }
data = source.data, width = source.width, height = source.height;
source.data = nullptr;
return *this;
}
Image::Image() : data(nullptr) {
}
Image::Image(const string &filename, const Color &alpha) : data(nullptr) {
load(filename, alpha);
}
Image::Image(const uint32_t *data, const Size &size) {
load(data, size);
}
Image::Image(const Image &source) : data(nullptr) {
operator=(source);
}
Image::Image(Image &&source) : data(nullptr) {
operator=(std::forward<Image>(source));
}
Image::~Image() {
if(data) delete[] data;
}
//Object //Object
//====== //======
@ -656,8 +735,29 @@ Button::~Button() {
//Canvas //Canvas
//====== //======
uint32_t* Canvas::buffer() { uint32_t* Canvas::data() {
return p.buffer(); return state.data;
}
bool Canvas::setImage(const Image &image) {
if(image.data == nullptr || image.width == 0 || image.height == 0) return false;
state.width = image.width;
state.height = image.height;
setSize({ state.width, state.height });
memcpy(state.data, image.data, state.width * state.height * sizeof(uint32_t));
return true;
}
void Canvas::setSize(const Size &size) {
state.width = size.width;
state.height = size.height;
delete[] state.data;
state.data = new uint32_t[size.width * size.height];
return p.setSize(size);
}
Size Canvas::size() {
return { state.width, state.height };
} }
void Canvas::update() { void Canvas::update() {
@ -665,14 +765,18 @@ void Canvas::update() {
} }
Canvas::Canvas(): Canvas::Canvas():
state(*new State),
base_from_member<pCanvas&>(*new pCanvas(*this)), base_from_member<pCanvas&>(*new pCanvas(*this)),
Widget(base_from_member<pCanvas&>::value), Widget(base_from_member<pCanvas&>::value),
p(base_from_member<pCanvas&>::value) { p(base_from_member<pCanvas&>::value) {
state.data = new uint32_t[state.width * state.height];
p.constructor(); p.constructor();
} }
Canvas::~Canvas() { Canvas::~Canvas() {
p.destructor(); p.destructor();
delete[] state.data;
delete &state;
} }
//CheckBox //CheckBox

View File

@ -41,6 +41,12 @@ enum : unsigned {
MinimumSize = 0u, MinimumSize = 0u,
}; };
struct Color {
uint8_t red, green, blue, alpha;
inline Color() : red(0), green(0), blue(0), alpha(255) {}
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
};
struct Geometry { struct Geometry {
signed x, y; signed x, y;
unsigned width, height; unsigned width, height;
@ -48,16 +54,37 @@ struct Geometry {
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {} inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
}; };
struct Position {
signed x, y;
inline Position() : x(0), y(0) {}
inline Position(signed x, signed y) : x(x), y(y) {}
};
struct Size {
unsigned width, height;
inline Size() : width(0), height(0) {}
inline Size(unsigned width, unsigned height) : width(width), height(height) {}
};
struct Font { struct Font {
nall::string description; nall::string description;
Geometry geometry(const nall::string &text); Geometry geometry(const nall::string &text);
Font(const nall::string &description = ""); Font(const nall::string &description = "");
}; };
struct Color { struct Image {
uint8_t red, green, blue, alpha; uint32_t *data;
inline Color() : red(0), green(0), blue(0), alpha(255) {} unsigned width, height;
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {} bool load(const nall::string &filename, const Color &alpha = Color{255, 255, 255});
void load(const uint32_t *data, const Size &size);
Image& operator=(const Image &source);
Image& operator=(Image &&source);
Image();
Image(const nall::string &filename, const Color &alpha = Color{255, 255, 255});
Image(const uint32_t *data, const Size &size);
Image(const Image &source);
Image(Image &&source);
~Image();
}; };
struct Object { struct Object {
@ -302,11 +329,16 @@ struct Button : private nall::base_from_member<pButton&>, Widget {
}; };
struct Canvas : private nall::base_from_member<pCanvas&>, Widget { struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
uint32_t* buffer(); uint32_t* data();
bool setImage(const Image &image);
void setSize(const Size &size);
Size size();
void update(); void update();
Canvas(); Canvas();
~Canvas(); ~Canvas();
struct State;
State &state;
pCanvas &p; pCanvas &p;
}; };

View File

@ -1,6 +1,6 @@
void HorizontalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) { void HorizontalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) {
for(auto &child : children) if(child.sizable == &sizable) return; for(auto &child : children) if(child.sizable == &sizable) return;
children.append({ &sizable, width, height, spacing }); children.append({ &sizable, size.width, size.height, spacing });
synchronizeLayout(); synchronizeLayout();
if(window()) window()->synchronizeLayout(); if(window()) window()->synchronizeLayout();
} }

View File

@ -1,5 +1,5 @@
struct HorizontalLayout : public Layout { struct HorizontalLayout : public Layout {
void append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing = 0); void append(Sizable &sizable, const Size &size, unsigned spacing = 0);
void append(Sizable &sizable); void append(Sizable &sizable);
bool enabled(); bool enabled();
Geometry minimumGeometry(); Geometry minimumGeometry();

View File

@ -1,6 +1,6 @@
void VerticalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) { void VerticalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) {
for(auto &child : children) if(child.sizable == &sizable) return; for(auto &child : children) if(child.sizable == &sizable) return;
children.append({ &sizable, width, height, spacing }); children.append({ &sizable, size.width, size.height, spacing });
synchronizeLayout(); synchronizeLayout();
if(window()) window()->synchronizeLayout(); if(window()) window()->synchronizeLayout();
} }

View File

@ -1,5 +1,5 @@
struct VerticalLayout : public Layout { struct VerticalLayout : public Layout {
void append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing = 0); void append(Sizable &sizable, const Size &size, unsigned spacing = 0);
void append(Sizable &sizable); void append(Sizable &sizable);
bool enabled(); bool enabled();
Geometry minimumGeometry(); Geometry minimumGeometry();

View File

@ -119,6 +119,18 @@ struct Button::State {
} }
}; };
struct Canvas::State {
uint32_t *data;
unsigned width;
unsigned height;
State() {
data = nullptr;
width = 256;
height = 256;
}
};
struct CheckBox::State { struct CheckBox::State {
bool checked; bool checked;
string text; string text;

View File

@ -231,8 +231,7 @@ struct pCanvas : public pWidget {
Canvas &canvas; Canvas &canvas;
cairo_surface_t *surface; cairo_surface_t *surface;
uint32_t* buffer(); void setSize(const Size &size);
void setGeometry(const Geometry &geometry);
void update(); void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}

View File

@ -6,33 +6,21 @@ static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self)
return true; return true;
} }
uint32_t* pCanvas::buffer() { void pCanvas::setSize(const Size &size) {
return (uint32_t*)cairo_image_surface_get_data(surface); cairo_surface_destroy(surface);
} surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height);
void pCanvas::setGeometry(const Geometry &geometry) {
if(geometry.width != cairo_image_surface_get_width (surface)
|| geometry.height != cairo_image_surface_get_height(surface)
) {
cairo_surface_destroy(surface);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, geometry.width, geometry.height);
}
pWidget::setGeometry(geometry);
update();
} }
void pCanvas::update() { void pCanvas::update() {
memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
if(gtk_widget_get_realized(gtkWidget) == false) return; if(gtk_widget_get_realized(gtkWidget) == false) return;
gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true); gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true);
} }
void pCanvas::constructor() { void pCanvas::constructor() {
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 256, 256); surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height);
memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
gtkWidget = gtk_drawing_area_new(); gtkWidget = gtk_drawing_area_new();
GdkColor color;
color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color);
gtk_widget_set_double_buffered(gtkWidget, false); gtk_widget_set_double_buffered(gtkWidget, false);
gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK); gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK);
g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);

View File

@ -2,8 +2,10 @@
#define PHOENIX_HPP #define PHOENIX_HPP
#include <nall/array.hpp> #include <nall/array.hpp>
#include <nall/bmp.hpp>
#include <nall/config.hpp> #include <nall/config.hpp>
#include <nall/function.hpp> #include <nall/function.hpp>
#include <nall/png.hpp>
#include <nall/reference_array.hpp> #include <nall/reference_array.hpp>
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
#include <nall/string.hpp> #include <nall/string.hpp>

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Sun Oct 23 22:41:00 2011 ** Created: Wed Nov 2 21:16:00 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0) ** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -282,8 +282,7 @@ public:
QtCanvas(pCanvas &self); QtCanvas(pCanvas &self);
} *qtCanvas; } *qtCanvas;
uint32_t* buffer(); void setSize(const Size &size);
void setGeometry(const Geometry &geometry);
void update(); void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}

View File

@ -1,21 +1,17 @@
uint32_t* pCanvas::buffer() { void pCanvas::setSize(const Size &size) {
return (uint32_t*)qtImage->bits(); delete qtImage;
} qtImage = new QImage(size.width, size.height, QImage::Format_RGB32);
void pCanvas::setGeometry(const Geometry &geometry) {
qtImage = new QImage(geometry.width, geometry.height, QImage::Format_RGB32);
qtImage->fill(0);
update();
pWidget::setGeometry(geometry);
} }
void pCanvas::update() { void pCanvas::update() {
memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
qtCanvas->update(); qtCanvas->update();
} }
void pCanvas::constructor() { void pCanvas::constructor() {
qtWidget = qtCanvas = new QtCanvas(*this); qtWidget = qtCanvas = new QtCanvas(*this);
qtImage = new QImage(256, 256, QImage::Format_RGB32); qtImage = new QImage(canvas.state.width, canvas.state.height, QImage::Format_RGB32);
memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
pWidget::synchronizeState(); pWidget::synchronizeState();
update(); update();
@ -36,6 +32,13 @@ void pCanvas::orphan() {
void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) { void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) {
QPainter painter(self.qtCanvas); QPainter painter(self.qtCanvas);
painter.drawImage(0, 0, *self.qtImage); painter.drawImage(0, 0, *self.qtImage);
//this will scale the source image to fit the target widget size (nearest-neighbor):
//painter.drawImage(
// QRect(0, 0, geometry().width(), geometry().height()),
// *self.qtImage,
// QRect(0, 0, self.canvas.state.width, self.canvas.state.height)
//);
} }
pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) { pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) {

View File

@ -185,7 +185,7 @@ struct pButton : public pWidget {
struct pCanvas : public pWidget { struct pCanvas : public pWidget {
Canvas &canvas; Canvas &canvas;
uint32_t* buffer(); void setSize(const Size &size);
void update(); void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}

View File

@ -1,5 +1,4 @@
uint32_t* pCanvas::buffer() { void pCanvas::setSize(const Size &size) {
return 0;
} }
void pCanvas::update() { void pCanvas::update() {

View File

@ -153,23 +153,10 @@ void OS_processDialogMessage(MSG &msg) {
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
} }
wchar_t className[256]; if(!IsDialogMessage(GetForegroundWindow(), &msg)) {
GetClassName(msg.hwnd, className, 255); TranslateMessage(&msg);
DispatchMessage(&msg);
//if this HWND accepts tabs to move between controls ...
if(!wcscmp(className, L"BUTTON") //Button, CheckBox, RadioBox
|| !wcscmp(className, L"COMBOBOX") //ComboBox
|| !wcscmp(className, L"EDIT") //HexEdit, LineEdit, TextEdit
|| !wcscmp(className, L"SCROLLBAR") //HorizontalScrollBar, VerticalScrollBar
|| !wcscmp(className, TRACKBAR_CLASS) //HorizontalSlider, VerticalSlider
|| !wcscmp(className, WC_LISTVIEW) //ListView
) {
//... return if the message is a dialog command
if(IsDialogMessage(msg.hwnd, &msg)) return;
} }
TranslateMessage(&msg);
DispatchMessage(&msg);
} }
void pOS::quit() { void pOS::quit() {
@ -195,7 +182,7 @@ void pOS::initialize() {
wc.cbClsExtra = 0; wc.cbClsExtra = 0;
wc.cbWndExtra = 0; wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0); wc.hInstance = GetModuleHandle(0);

View File

@ -214,10 +214,9 @@ struct pButton : public pWidget {
struct pCanvas : public pWidget { struct pCanvas : public pWidget {
Canvas &canvas; Canvas &canvas;
uint32_t *bufferRGB; uint32_t *data;
uint32_t* buffer(); void setSize(const Size &size);
void setGeometry(const Geometry &geometry);
void update(); void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}

View File

@ -1,29 +1,30 @@
static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(msg == WM_GETDLGCODE) {
return DLGC_STATIC | DLGC_WANTCHARS;
}
if(msg == WM_PAINT) { if(msg == WM_PAINT) {
Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(object && dynamic_cast<Canvas*>(object)) { if(object && dynamic_cast<Canvas*>(object)) {
Canvas &canvas = (Canvas&)*object; Canvas &canvas = (Canvas&)*object;
canvas.update(); canvas.update();
} }
return TRUE;
} }
return DefWindowProc(hwnd, msg, wparam, lparam); return DefWindowProc(hwnd, msg, wparam, lparam);
} }
uint32_t* pCanvas::buffer() { void pCanvas::setSize(const Size &size) {
return bufferRGB; delete[] data;
} data = new uint32_t[size.width * size.height];
memcpy(data, canvas.state.data, size.width * size.height * sizeof(uint32_t));
void pCanvas::setGeometry(const Geometry &geometry) {
delete[] bufferRGB;
bufferRGB = new uint32_t[geometry.width * geometry.height]();
pWidget::setGeometry(geometry);
update();
} }
void pCanvas::update() { void pCanvas::update() {
RECT rc; RECT rc;
GetClientRect(hwnd, &rc); GetClientRect(hwnd, &rc);
unsigned width = rc.right, height = rc.bottom; unsigned width = canvas.state.width, height = canvas.state.height; //rc.right, height = rc.bottom;
BITMAPINFO bmi; BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO)); memset(&bmi, 0, sizeof(BITMAPINFO));
@ -37,13 +38,14 @@ void pCanvas::update() {
PAINTSTRUCT ps; PAINTSTRUCT ps;
BeginPaint(hwnd, &ps); BeginPaint(hwnd, &ps);
SetDIBitsToDevice(ps.hdc, 0, 0, width, height, 0, 0, 0, height, (void*)bufferRGB, &bmi, DIB_RGB_COLORS); SetDIBitsToDevice(ps.hdc, 0, 0, width, height, 0, 0, 0, height, (void*)data, &bmi, DIB_RGB_COLORS);
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
InvalidateRect(hwnd, 0, false); InvalidateRect(hwnd, 0, false);
} }
void pCanvas::constructor() { void pCanvas::constructor() {
bufferRGB = new uint32_t[256 * 256](); data = new uint32_t[canvas.state.width * canvas.state.height];
memcpy(data, canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas);
synchronize(); synchronize();
@ -51,6 +53,7 @@ void pCanvas::constructor() {
void pCanvas::destructor() { void pCanvas::destructor() {
DestroyWindow(hwnd); DestroyWindow(hwnd);
delete[] data;
} }
void pCanvas::orphan() { void pCanvas::orphan() {

View File

@ -30,6 +30,10 @@ static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPA
Label *label = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA); Label *label = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!window || !label) return DefWindowProc(hwnd, msg, wparam, lparam); if(!window || !label) return DefWindowProc(hwnd, msg, wparam, lparam);
if(msg == WM_GETDLGCODE) {
return DLGC_STATIC | DLGC_WANTCHARS;
}
if(msg == WM_ERASEBKGND) { if(msg == WM_ERASEBKGND) {
//background is erased during WM_PAINT to prevent flickering //background is erased during WM_PAINT to prevent flickering
return TRUE; return TRUE;

View File

@ -34,7 +34,7 @@ string pTextEdit::text() {
void pTextEdit::constructor() { void pTextEdit::constructor() {
hwnd = CreateWindowEx( hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", L"", WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? ES_AUTOHSCROLL : 0), WS_CHILD | WS_TABSTOP | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? ES_AUTOHSCROLL : 0),
0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0
); );
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit);

View File

@ -18,5 +18,6 @@ void pViewport::orphan() {
} }
static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(msg == WM_GETDLGCODE) return DLGC_STATIC | DLGC_WANTCHARS;
return DefWindowProc(hwnd, msg, wparam, lparam); return DefWindowProc(hwnd, msg, wparam, lparam);
} }

View File

@ -1,8 +1,8 @@
DipSwitches *dipSwitches = 0; DipSwitches *dipSwitches = 0;
DipSwitch::DipSwitch() { DipSwitch::DipSwitch() {
append(name, ~0, 0, 5); append(name, { ~0, 0 }, 5);
append(value, ~0, 0); append(value, { ~0, 0 }, 0);
} }
DipSwitches::DipSwitches() { DipSwitches::DipSwitches() {
@ -13,10 +13,10 @@ DipSwitches::DipSwitches() {
append(layout); append(layout);
for(unsigned n = 0; n < 8; n++) for(unsigned n = 0; n < 8; n++)
layout.append(dip[n], ~0, 0, 5); layout.append(dip[n], { ~0, 0 }, 5);
layout.append(controlLayout, ~0, 0, 5); layout.append(controlLayout, { ~0, 0 }, 5);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(acceptButton, 0, 0); controlLayout.append(acceptButton, { 0, 0 }, 0);
setGeometry({ 128, 128, 400, layout.minimumGeometry().height }); setGeometry({ 128, 128, 400, layout.minimumGeometry().height });
windowManager->append(this, "DipSwitches"); windowManager->append(this, "DipSwitches");

View File

@ -10,14 +10,14 @@ FileBrowser::FileBrowser() {
openButton.setText("Open"); openButton.setText("Open");
append(layout); append(layout);
layout.append(pathLayout, ~0, 0, 5); layout.append(pathLayout, { ~0, 0 }, 5);
pathLayout.append(pathEdit, ~0, 0, 5); pathLayout.append(pathEdit, { ~0, 0 }, 5);
pathLayout.append(pathBrowse, 0, 0, 5); pathLayout.append(pathBrowse, { 0, 0 }, 5);
pathLayout.append(pathUp, 0, 0); pathLayout.append(pathUp, { 0, 0 });
layout.append(fileList, ~0, ~0, 5); layout.append(fileList, { ~0, ~0 }, 5);
layout.append(controlLayout, ~0, 0); layout.append(controlLayout, { ~0, 0 });
controlLayout.append(filterLabel, ~0, 0, 5); controlLayout.append(filterLabel, { ~0, 0 }, 5);
controlLayout.append(openButton, 80, 0); controlLayout.append(openButton, { 80, 0 });
pathEdit.onActivate = [&] { pathEdit.onActivate = [&] {
string path = pathEdit.text(); string path = pathEdit.text();

View File

@ -2,9 +2,9 @@ SlotLoader *slotLoader = 0;
SlotLoaderPath::SlotLoaderPath() { SlotLoaderPath::SlotLoaderPath() {
browse.setText("Browse ..."); browse.setText("Browse ...");
append(label, 40, 0, 5); append(label, { 40, 0 }, 5);
append(path, ~0, 0, 5); append(path, { ~0, 0 }, 5);
append(browse, 80, 0); append(browse, { 80, 0 }, 0);
} }
SlotLoader::SlotLoader() { SlotLoader::SlotLoader() {
@ -15,12 +15,12 @@ SlotLoader::SlotLoader() {
loadButton.setText("Load"); loadButton.setText("Load");
append(layout); append(layout);
layout.append(base, ~0, 0, 5); layout.append(base, { ~0, 0 }, 5);
layout.append(slot[0], ~0, 0, 5); layout.append(slot[0], { ~0, 0 }, 5);
layout.append(slot[1], ~0, 0, 5); layout.append(slot[1], { ~0, 0 }, 5);
layout.append(controlLayout, ~0, 0); layout.append(controlLayout, { ~0, 0 }, 0);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(loadButton, 80, 0); controlLayout.append(loadButton, { 80, 0 }, 0);
setGeometry({ 128, 128, 500, layout.minimumGeometry().height }); setGeometry({ 128, 128, 500, layout.minimumGeometry().height });
windowManager->append(this, "SlotLoader"); windowManager->append(this, "SlotLoader");

View File

@ -27,7 +27,7 @@ void Application::run() {
} }
Application::Application(int argc, char **argv) { Application::Application(int argc, char **argv) {
title = "bsnes v083.09"; title = "bsnes v083.10";
application = this; application = this;
quit = false; quit = false;

View File

@ -41,22 +41,22 @@ AdvancedSettings::AdvancedSettings() {
if(list[n] == input.default_driver() && config->input.driver == "") inputDriver.setSelection(n); if(list[n] == input.default_driver() && config->input.driver == "") inputDriver.setSelection(n);
} }
append(title, ~0, 0, 5); append(title, { ~0, 0 }, 5);
append(driverLabel, ~0, 0); append(driverLabel, { ~0, 0 }, 0);
append(driverLayout, ~0, 0, 5); append(driverLayout, { ~0, 0 }, 5);
driverLayout.append(videoLabel, 0, 0, 5); driverLayout.append(videoLabel, { 0, 0 }, 5);
driverLayout.append(videoDriver, ~0, 0, 5); driverLayout.append(videoDriver, { ~0, 0 }, 5);
driverLayout.append(audioLabel, 0, 0, 5); driverLayout.append(audioLabel, { 0, 0 }, 5);
driverLayout.append(audioDriver, ~0, 0, 5); driverLayout.append(audioDriver, { ~0, 0 }, 5);
driverLayout.append(inputLabel, 0, 0, 5); driverLayout.append(inputLabel, { 0, 0 }, 5);
driverLayout.append(inputDriver, ~0, 0); driverLayout.append(inputDriver, { ~0, 0 }, 0);
append(focusPolicyLabel, ~0, 0); append(focusPolicyLabel, { ~0, 0 }, 0);
append(focusPolicyLayout, ~0, 0, 5); append(focusPolicyLayout, { ~0, 0 }, 5);
focusPolicyLayout.append(focusPolicy[0], ~0, 0, 5); focusPolicyLayout.append(focusPolicy[0], { ~0, 0 }, 5);
focusPolicyLayout.append(focusPolicy[1], ~0, 0, 5); focusPolicyLayout.append(focusPolicy[1], { ~0, 0 }, 5);
focusPolicyLayout.append(focusPolicy[2], ~0, 0); focusPolicyLayout.append(focusPolicy[2], { ~0, 0 }, 0);
append(spacer, ~0, ~0); append(spacer, { ~0, ~0 }, 0);
append(aboutLabel, ~0, 0); append(aboutLabel, { ~0, 0 }, 0);
videoDriver.onChange = [&] { videoDriver.onChange = [&] {
lstring list; lstring list;

View File

@ -1,9 +1,9 @@
AudioSettings *audioSettings = 0; AudioSettings *audioSettings = 0;
AudioSlider::AudioSlider() { AudioSlider::AudioSlider() {
append(name, 75, 0); append(name, { 75, 0 });
append(value, 75, 0); append(value, { 75, 0 });
append(slider, ~0, 0); append(slider, { ~0, 0 });
} }
unsigned AudioSlider::position() { unsigned AudioSlider::position() {
@ -68,20 +68,20 @@ AudioSettings::AudioSettings() {
gameBoy.base = 4194304; gameBoy.base = 4194304;
gameBoy.step = 131; gameBoy.step = 131;
append(title, ~0, 0, 5); append(title, { ~0, 0 }, 5);
append(outputLabel, ~0, 0); append(outputLabel, { ~0, 0 }, 0);
append(outputLayout, ~0, 0, 5); append(outputLayout, { ~0, 0 }, 5);
outputLayout.append(frequencyLabel, 0, 0, 5); outputLayout.append(frequencyLabel, { 0, 0 }, 5);
outputLayout.append(frequencySelection, ~0, 0, 5); outputLayout.append(frequencySelection, { ~0, 0 }, 5);
outputLayout.append(latencyLabel, 0, 0, 5); outputLayout.append(latencyLabel, { 0, 0 }, 5);
outputLayout.append(latencySelection, ~0, 0, 5); outputLayout.append(latencySelection, { ~0, 0 }, 5);
outputLayout.append(resamplerLabel, 0, 0, 5); outputLayout.append(resamplerLabel, { 0, 0 }, 5);
outputLayout.append(resamplerSelection, ~0, 0); outputLayout.append(resamplerSelection, { ~0, 0 }, 0);
append(volume, ~0, 0, 5); append(volume, { ~0, 0 }, 5);
append(frequencyAdjustmentLabel, ~0, 0); append(frequencyAdjustmentLabel, { ~0, 0 }, 0);
append(nes, ~0, 0); append(nes, { ~0, 0 }, 0);
append(snes, ~0, 0); append(snes, { ~0, 0 }, 0);
append(gameBoy, ~0, 0); append(gameBoy, { ~0, 0 }, 0);
frequencySelection.setSelection( frequencySelection.setSelection(
config->audio.frequency == 32000 ? 0 : config->audio.frequency == 32000 ? 0 :

View File

@ -15,18 +15,18 @@ InputSettings::InputSettings() : activeInput(0) {
} }
primaryChange(); primaryChange();
append(title, ~0, 0, 5); append(title, { ~0, 0 }, 5);
append(selectionLayout, ~0, 0, 5); append(selectionLayout, { ~0, 0 }, 5);
selectionLayout.append(primary, ~0, 0, 5); selectionLayout.append(primary, { ~0, 0 }, 5);
selectionLayout.append(secondary, ~0, 0, 5); selectionLayout.append(secondary, { ~0, 0 }, 5);
selectionLayout.append(tertiary, ~0, 0); selectionLayout.append(tertiary, { ~0, 0 }, 0);
append(inputList, ~0, ~0, 5); append(inputList, { ~0, ~0 }, 5);
append(controlLayout, ~0, 0); append(controlLayout, { ~0, 0 }, 0);
controlLayout.append(assignPrimary, 100, 0, 5); controlLayout.append(assignPrimary, { 100, 0 }, 5);
controlLayout.append(assignSecondary, 100, 0, 5); controlLayout.append(assignSecondary, { 100, 0 }, 5);
controlLayout.append(assignTertiary, 100, 0, 5); controlLayout.append(assignTertiary, { 100, 0 }, 5);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(clearButton, 80, 0); controlLayout.append(clearButton, { 80, 0 }, 0);
primary.onChange = { &InputSettings::primaryChange, this }; primary.onChange = { &InputSettings::primaryChange, this };
secondary.onChange = { &InputSettings::secondaryChange, this }; secondary.onChange = { &InputSettings::secondaryChange, this };

View File

@ -5,14 +5,14 @@
#include "advanced.cpp" #include "advanced.cpp"
SettingsWindow *settingsWindow = 0; SettingsWindow *settingsWindow = 0;
void SettingsLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) { void SettingsLayout::append(Sizable &sizable, const Size &size, unsigned spacing) {
layout.append(sizable, width, height, spacing); layout.append(sizable, size, spacing);
} }
SettingsLayout::SettingsLayout() { SettingsLayout::SettingsLayout() {
setMargin(5); setMargin(5);
HorizontalLayout::append(spacer, 120, ~0, 5); HorizontalLayout::append(spacer, { 120, ~0 }, 5);
HorizontalLayout::append(layout, ~0, ~0); HorizontalLayout::append(layout, { ~0, ~0 }, 0);
} }
SettingsWindow::SettingsWindow() { SettingsWindow::SettingsWindow() {
@ -34,7 +34,7 @@ SettingsWindow::SettingsWindow() {
advancedSettings = new AdvancedSettings; advancedSettings = new AdvancedSettings;
append(layout); append(layout);
layout.append(panelList, 120, ~0, 5); layout.append(panelList, { 120, ~0 }, 5);
append(*videoSettings); append(*videoSettings);
append(*audioSettings); append(*audioSettings);
append(*inputSettings); append(*inputSettings);

View File

@ -2,7 +2,7 @@ struct SettingsLayout : HorizontalLayout {
Widget spacer; Widget spacer;
VerticalLayout layout; VerticalLayout layout;
void append(Sizable &widget, unsigned width, unsigned height, unsigned spacing = 0); void append(Sizable &widget, const Size &size, unsigned spacing = 0);
SettingsLayout(); SettingsLayout();
}; };

View File

@ -1,9 +1,9 @@
VideoSettings *videoSettings = 0; VideoSettings *videoSettings = 0;
VideoSlider::VideoSlider() { VideoSlider::VideoSlider() {
append(name, 75, 0); append(name, { 75, 0 });
append(value, 75, 0); append(value, { 75, 0 });
append(slider, ~0, 0); append(slider, { ~0, 0 });
} }
VideoSettings::VideoSettings() { VideoSettings::VideoSettings() {
@ -36,24 +36,24 @@ VideoSettings::VideoSettings() {
compositor[2].setText("Always"); compositor[2].setText("Always");
RadioBox::group(compositor[0], compositor[1], compositor[2]); RadioBox::group(compositor[0], compositor[1], compositor[2]);
append(title, ~0, 0, 5); append(title, { ~0, 0 }, 5);
append(colorAdjustment, ~0, 0); append(colorAdjustment, { ~0, 0 }, 0);
append(brightness, ~0, 0); append(brightness, { ~0, 0 }, 0);
append(contrast, ~0, 0); append(contrast, { ~0, 0 }, 0);
append(gamma, ~0, 0, 5); append(gamma, { ~0, 0 }, 5);
append(overscanAdjustment, ~0, 0); append(overscanAdjustment, { ~0, 0 }, 0);
append(overscanHorizontal, ~0, 0); append(overscanHorizontal, { ~0, 0 }, 0);
append(overscanVertical, ~0, 0, 5); append(overscanVertical, { ~0, 0 }, 5);
append(fullScreenMode, ~0, 0); append(fullScreenMode, { ~0, 0 }, 0);
append(fullScreenLayout, ~0, 0, 5); append(fullScreenLayout, { ~0, 0 }, 5);
fullScreenLayout.append(fullScreen[0], ~0, 0, 5); fullScreenLayout.append(fullScreen[0], { ~0, 0 }, 5);
fullScreenLayout.append(fullScreen[1], ~0, 0, 5); fullScreenLayout.append(fullScreen[1], { ~0, 0 }, 5);
fullScreenLayout.append(fullScreen[2], ~0, 0); fullScreenLayout.append(fullScreen[2], { ~0, 0 }, 0);
append(compositorLabel, ~0, 0); append(compositorLabel, { ~0, 0 }, 0);
append(compositorLayout, ~0, 0); append(compositorLayout, { ~0, 0 }, 0);
compositorLayout.append(compositor[0], ~0, 0, 5); compositorLayout.append(compositor[0], { ~0, 0 }, 5);
compositorLayout.append(compositor[1], ~0, 0, 5); compositorLayout.append(compositor[1], { ~0, 0 }, 5);
compositorLayout.append(compositor[2], ~0, 0); compositorLayout.append(compositor[2], { ~0, 0 }, 0);
brightness.slider.setPosition(config->video.brightness); brightness.slider.setPosition(config->video.brightness);
contrast.slider.setPosition(config->video.contrast); contrast.slider.setPosition(config->video.contrast);
@ -95,9 +95,6 @@ void VideoSettings::synchronize() {
config->video.gamma = gamma.slider.position(); config->video.gamma = gamma.slider.position();
config->video.maskOverscanHorizontal = overscanHorizontal.slider.position(); config->video.maskOverscanHorizontal = overscanHorizontal.slider.position();
config->video.maskOverscanVertical = overscanVertical.slider.position(); config->video.maskOverscanVertical = overscanVertical.slider.position();
if(fullScreen[0].checked()) { config->video.fullScreenMode = 0; }
if(fullScreen[1].checked()) { config->video.fullScreenMode = 1; }
if(fullScreen[2].checked()) { config->video.fullScreenMode = 2; }
brightness.value.setText({ config->video.brightness, "%" }); brightness.value.setText({ config->video.brightness, "%" });
contrast.value.setText({ config->video.contrast, "%" }); contrast.value.setText({ config->video.contrast, "%" });

View File

@ -11,12 +11,12 @@ CheatDatabase::CheatDatabase() {
acceptButton.setText("Add Codes"); acceptButton.setText("Add Codes");
append(layout); append(layout);
layout.append(cheatList, ~0, ~0, 5); layout.append(cheatList, { ~0, ~0 }, 5);
layout.append(controlLayout, ~0, 0); layout.append(controlLayout, { ~0, 0 }, 0);
controlLayout.append(selectAllButton, 100, 0, 5); controlLayout.append(selectAllButton, { 100, 0 }, 5);
controlLayout.append(unselectAllButton, 100, 0); controlLayout.append(unselectAllButton, { 100, 0 }, 0);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(acceptButton, 80, 0); controlLayout.append(acceptButton, { 80, 0 }, 0);
selectAllButton.onTick = [&] { selectAllButton.onTick = [&] {
for(unsigned n = 0; n < cheatCode.size(); n++) cheatList.setChecked(n, true); for(unsigned n = 0; n < cheatCode.size(); n++) cheatList.setChecked(n, true);

View File

@ -16,18 +16,18 @@ CheatEditor::CheatEditor() {
append(layout); append(layout);
layout.setMargin(5); layout.setMargin(5);
layout.append(cheatList, ~0, ~0, 5); layout.append(cheatList, { ~0, ~0 }, 5);
layout.append(codeLayout, ~0, 0, 5); layout.append(codeLayout, { ~0, 0 }, 5);
codeLayout.append(codeLabel, 80, 0); codeLayout.append(codeLabel, { 80, 0 }, 0);
codeLayout.append(codeEdit, ~0, 0); codeLayout.append(codeEdit, { ~0, 0 }, 0);
layout.append(descLayout, ~0, 0, 5); layout.append(descLayout, { ~0, 0 }, 5);
descLayout.append(descLabel, 80, 0); descLayout.append(descLabel, { 80, 0 }, 0);
descLayout.append(descEdit, ~0, 0); descLayout.append(descEdit, { ~0, 0 }, 0);
layout.append(controlLayout, ~0, 0); layout.append(controlLayout, { ~0, 0 }, 0);
controlLayout.append(findButton, 100, 0); controlLayout.append(findButton, { 100, 0 }, 0);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(clearAllButton, 80, 0, 5); controlLayout.append(clearAllButton, { 80, 0 }, 5);
controlLayout.append(clearButton, 80, 0); controlLayout.append(clearButton, { 80, 0 }, 0);
for(unsigned n = 0; n < 128; n++) cheatList.append("", "", ""); for(unsigned n = 0; n < 128; n++) cheatList.append("", "", "");
updateUI(); updateUI();

View File

@ -14,15 +14,15 @@ StateManager::StateManager() {
append(layout); append(layout);
layout.setMargin(5); layout.setMargin(5);
layout.append(stateList, ~0, ~0, 5); layout.append(stateList, { ~0, ~0 }, 5);
layout.append(descLayout, ~0, 0, 5); layout.append(descLayout, { ~0, 0 }, 5);
descLayout.append(descLabel, 0, 0, 5); descLayout.append(descLabel, { 0, 0 }, 5);
descLayout.append(descEdit, ~0, 0); descLayout.append(descEdit, { ~0, 0 }, 0);
layout.append(controlLayout, ~0, 0); layout.append(controlLayout, { ~0, 0 }, 0);
controlLayout.append(spacer, ~0, 0); controlLayout.append(spacer, { ~0, 0 }, 0);
controlLayout.append(loadButton, 80, 0, 5); controlLayout.append(loadButton, { 80, 0 }, 5);
controlLayout.append(saveButton, 80, 0, 5); controlLayout.append(saveButton, { 80, 0 }, 5);
controlLayout.append(eraseButton, 80, 0); controlLayout.append(eraseButton, { 80, 0 }, 0);
for(unsigned n = 0; n < 32; n++) stateList.append(decimal<2>(n + 1), "(empty)"); for(unsigned n = 0; n < 32; n++) stateList.append(decimal<2>(n + 1), "(empty)");
stateList.autoSizeColumns(); stateList.autoSizeColumns();

View File

@ -47,6 +47,7 @@ void Utility::resizeMainWindow(bool shrink) {
unsigned width = geometry.width, height = geometry.height; unsigned width = geometry.width, height = geometry.height;
switch(interface->mode()) { switch(interface->mode()) {
case Interface::Mode::None: return;
case Interface::Mode::NES: width = 256, height = 240; break; case Interface::Mode::NES: width = 256, height = 240; break;
case Interface::Mode::SNES: width = 256, height = 240; break; case Interface::Mode::SNES: width = 256, height = 240; break;
case Interface::Mode::GameBoy: width = 160, height = 144; break; case Interface::Mode::GameBoy: width = 160, height = 144; break;