mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
bf78e66027
commit
891f1ab7af
|
@ -7,9 +7,11 @@
|
|||
|
||||
namespace nall {
|
||||
template<typename T> struct reference_array {
|
||||
struct exception_out_of_bounds{};
|
||||
|
||||
protected:
|
||||
typedef typename std::remove_reference<T>::type *Tptr;
|
||||
Tptr *pool;
|
||||
typedef typename std::remove_reference<T>::type type_t;
|
||||
type_t **pool;
|
||||
unsigned poolsize, buffersize;
|
||||
|
||||
public:
|
||||
|
@ -26,7 +28,7 @@ namespace nall {
|
|||
void reserve(unsigned newsize) {
|
||||
if(newsize == poolsize) return;
|
||||
|
||||
pool = (Tptr*)realloc(pool, newsize * sizeof(T));
|
||||
pool = (type_t**)realloc(pool, sizeof(type_t*) * newsize);
|
||||
poolsize = newsize;
|
||||
buffersize = min(buffersize, newsize);
|
||||
}
|
||||
|
@ -37,13 +39,13 @@ namespace nall {
|
|||
}
|
||||
|
||||
template<typename... Args>
|
||||
bool append(const T& data, Args&&... args) {
|
||||
bool append(type_t& data, Args&&... args) {
|
||||
bool result = append(data);
|
||||
append(std::forward<Args>(args)...);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool append(const T data) {
|
||||
bool append(type_t& data) {
|
||||
for(unsigned index = 0; index < buffersize; index++) {
|
||||
if(pool[index] == &data) return false;
|
||||
}
|
||||
|
@ -54,7 +56,7 @@ namespace nall {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool remove(const T data) {
|
||||
bool remove(type_t& data) {
|
||||
for(unsigned index = 0; index < buffersize; index++) {
|
||||
if(pool[index] == &data) {
|
||||
for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1];
|
||||
|
@ -77,8 +79,8 @@ namespace nall {
|
|||
if(pool) free(pool);
|
||||
buffersize = source.buffersize;
|
||||
poolsize = source.poolsize;
|
||||
pool = (Tptr*)malloc(sizeof(T) * poolsize);
|
||||
memcpy(pool, source.pool, sizeof(T) * buffersize);
|
||||
pool = (type_t**)malloc(sizeof(type_t*) * poolsize);
|
||||
memcpy(pool, source.pool, sizeof(type_t*) * buffersize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -92,20 +94,20 @@ namespace nall {
|
|||
return *this;
|
||||
}
|
||||
|
||||
inline T operator[](unsigned index) {
|
||||
if(index >= buffersize) throw "reference_array[] out of bounds";
|
||||
inline type_t& operator[](unsigned index) {
|
||||
if(index >= buffersize) throw exception_out_of_bounds();
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
inline const T operator[](unsigned index) const {
|
||||
if(index >= buffersize) throw "reference_array[] out of bounds";
|
||||
inline type_t& operator[](unsigned index) const {
|
||||
if(index >= buffersize) throw exception_out_of_bounds();
|
||||
return *pool[index];
|
||||
}
|
||||
|
||||
//iteration
|
||||
struct iterator {
|
||||
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(const reference_array &array, unsigned index) : array(array), index(index) {}
|
||||
private:
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "bandai-fcg.cpp"
|
||||
#include "konami-vrc1.cpp"
|
||||
#include "konami-vrc2.cpp"
|
||||
#include "konami-vrc3.cpp"
|
||||
#include "konami-vrc4.cpp"
|
||||
#include "konami-vrc6.cpp"
|
||||
#include "konami-vrc7.cpp"
|
||||
|
@ -8,6 +11,7 @@
|
|||
#include "nes-exrom.cpp"
|
||||
#include "nes-fxrom.cpp"
|
||||
#include "nes-gxrom.cpp"
|
||||
#include "nes-hkrom.cpp"
|
||||
#include "nes-nrom.cpp"
|
||||
#include "nes-pxrom.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 == "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-6") return new KonamiVRC6(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-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-256") return new NES_NROM(board, data, size);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -32,53 +32,7 @@ uint8 prg_read(unsigned addr) {
|
|||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.ram_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;
|
||||
}
|
||||
if(addr & 0x8000) return mmc3.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "mmc1.cpp"
|
||||
#include "mmc3.cpp"
|
||||
#include "mmc5.cpp"
|
||||
#include "mmc6.cpp"
|
||||
#include "vrc1.cpp"
|
||||
#include "vrc2.cpp"
|
||||
#include "vrc3.cpp"
|
||||
#include "vrc4.cpp"
|
||||
#include "vrc6.cpp"
|
||||
#include "vrc7.cpp"
|
||||
|
|
|
@ -89,6 +89,55 @@ void ram_write(unsigned addr, uint8 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() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -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) {
|
||||
}
|
||||
|
||||
};
|
|
@ -140,6 +140,7 @@ unsigned ciram_addr(unsigned addr) const {
|
|||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void power() {
|
||||
|
|
|
@ -14,7 +14,7 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
unsigned prgram = 0;
|
||||
unsigned chrram = chrrom == 0 ? 8192 : 0;
|
||||
|
||||
//print("iNES mapper: ", mapper, "\n");
|
||||
print("iNES mapper: ", mapper, "\n");
|
||||
|
||||
output.append("cartridge\n");
|
||||
|
||||
|
@ -41,9 +41,14 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
break;
|
||||
|
||||
case 4:
|
||||
//MMC3
|
||||
output.append("\tboard type:NES-TLROM\n");
|
||||
output.append("\t\tchip type:MMC3B\n");
|
||||
prgram = 8192;
|
||||
//MMC6
|
||||
//output.append("\tboard type:NES-HKROM\n");
|
||||
//output.append("\t\tchip type:MMC6\n");
|
||||
//prgram = 1024;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
|
@ -76,6 +81,10 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
case 21:
|
||||
case 23:
|
||||
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("\t\tchip type:VRC4\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;
|
||||
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:
|
||||
output.append("\tboard type:KONAMI-VRC-7\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\tchr rom=", chrrom, " ram=", chrram, "\n");
|
||||
|
||||
//print(output, "\n");
|
||||
print(output, "\n");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ string CPU::disassemble() {
|
|||
op(0xe6, inc, zpg);
|
||||
op(0xe8, inx, imp);
|
||||
op(0xe9, sbc, imm);
|
||||
op(0xea, nop, imp);
|
||||
op(0xec, cpx, abs);
|
||||
op(0xed, sbc, abs);
|
||||
op(0xee, inc, abs);
|
||||
|
|
|
@ -27,6 +27,85 @@ Font::Font(const string &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
|
||||
//======
|
||||
|
||||
|
@ -656,8 +735,29 @@ Button::~Button() {
|
|||
//Canvas
|
||||
//======
|
||||
|
||||
uint32_t* Canvas::buffer() {
|
||||
return p.buffer();
|
||||
uint32_t* Canvas::data() {
|
||||
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() {
|
||||
|
@ -665,14 +765,18 @@ void Canvas::update() {
|
|||
}
|
||||
|
||||
Canvas::Canvas():
|
||||
state(*new State),
|
||||
base_from_member<pCanvas&>(*new pCanvas(*this)),
|
||||
Widget(base_from_member<pCanvas&>::value),
|
||||
p(base_from_member<pCanvas&>::value) {
|
||||
state.data = new uint32_t[state.width * state.height];
|
||||
p.constructor();
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
p.destructor();
|
||||
delete[] state.data;
|
||||
delete &state;
|
||||
}
|
||||
|
||||
//CheckBox
|
||||
|
|
|
@ -41,6 +41,12 @@ enum : unsigned {
|
|||
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 {
|
||||
signed x, y;
|
||||
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) {}
|
||||
};
|
||||
|
||||
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 {
|
||||
nall::string description;
|
||||
Geometry geometry(const nall::string &text);
|
||||
Font(const nall::string &description = "");
|
||||
};
|
||||
|
||||
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 Image {
|
||||
uint32_t *data;
|
||||
unsigned width, height;
|
||||
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 {
|
||||
|
@ -302,11 +329,16 @@ struct Button : private nall::base_from_member<pButton&>, 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();
|
||||
|
||||
Canvas();
|
||||
~Canvas();
|
||||
struct State;
|
||||
State &state;
|
||||
pCanvas &p;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
children.append({ &sizable, width, height, spacing });
|
||||
children.append({ &sizable, size.width, size.height, spacing });
|
||||
synchronizeLayout();
|
||||
if(window()) window()->synchronizeLayout();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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);
|
||||
bool enabled();
|
||||
Geometry minimumGeometry();
|
||||
|
|
|
@ -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;
|
||||
children.append({ &sizable, width, height, spacing });
|
||||
children.append({ &sizable, size.width, size.height, spacing });
|
||||
synchronizeLayout();
|
||||
if(window()) window()->synchronizeLayout();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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);
|
||||
bool enabled();
|
||||
Geometry minimumGeometry();
|
||||
|
|
|
@ -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 {
|
||||
bool checked;
|
||||
string text;
|
||||
|
|
|
@ -231,8 +231,7 @@ struct pCanvas : public pWidget {
|
|||
Canvas &canvas;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
uint32_t* buffer();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setSize(const Size &size);
|
||||
void update();
|
||||
|
||||
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
|
||||
|
|
|
@ -6,33 +6,21 @@ static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
return (uint32_t*)cairo_image_surface_get_data(surface);
|
||||
}
|
||||
|
||||
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::setSize(const Size &size) {
|
||||
cairo_surface_destroy(surface);
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height);
|
||||
}
|
||||
|
||||
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;
|
||||
gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true);
|
||||
}
|
||||
|
||||
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();
|
||||
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_add_events(gtkWidget, GDK_EXPOSURE_MASK);
|
||||
g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
#define PHOENIX_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/bmp.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/png.hpp>
|
||||
#include <nall/reference_array.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
** 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)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
|
|
|
@ -282,8 +282,7 @@ public:
|
|||
QtCanvas(pCanvas &self);
|
||||
} *qtCanvas;
|
||||
|
||||
uint32_t* buffer();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setSize(const Size &size);
|
||||
void update();
|
||||
|
||||
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
uint32_t* pCanvas::buffer() {
|
||||
return (uint32_t*)qtImage->bits();
|
||||
}
|
||||
|
||||
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::setSize(const Size &size) {
|
||||
delete qtImage;
|
||||
qtImage = new QImage(size.width, size.height, QImage::Format_RGB32);
|
||||
}
|
||||
|
||||
void pCanvas::update() {
|
||||
memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t));
|
||||
qtCanvas->update();
|
||||
}
|
||||
|
||||
void pCanvas::constructor() {
|
||||
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();
|
||||
update();
|
||||
|
@ -36,6 +32,13 @@ void pCanvas::orphan() {
|
|||
void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) {
|
||||
QPainter painter(self.qtCanvas);
|
||||
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) {
|
||||
|
|
|
@ -185,7 +185,7 @@ struct pButton : public pWidget {
|
|||
struct pCanvas : public pWidget {
|
||||
Canvas &canvas;
|
||||
|
||||
uint32_t* buffer();
|
||||
void setSize(const Size &size);
|
||||
void update();
|
||||
|
||||
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
uint32_t* pCanvas::buffer() {
|
||||
return 0;
|
||||
void pCanvas::setSize(const Size &size) {
|
||||
}
|
||||
|
||||
void pCanvas::update() {
|
||||
|
|
|
@ -153,23 +153,10 @@ void OS_processDialogMessage(MSG &msg) {
|
|||
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
|
||||
}
|
||||
|
||||
wchar_t className[256];
|
||||
GetClassName(msg.hwnd, className, 255);
|
||||
|
||||
//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;
|
||||
if(!IsDialogMessage(GetForegroundWindow(), &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
void pOS::quit() {
|
||||
|
@ -195,7 +182,7 @@ void pOS::initialize() {
|
|||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
|
|
|
@ -214,10 +214,9 @@ struct pButton : public pWidget {
|
|||
|
||||
struct pCanvas : public pWidget {
|
||||
Canvas &canvas;
|
||||
uint32_t *bufferRGB;
|
||||
uint32_t *data;
|
||||
|
||||
uint32_t* buffer();
|
||||
void setGeometry(const Geometry &geometry);
|
||||
void setSize(const Size &size);
|
||||
void update();
|
||||
|
||||
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
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) {
|
||||
Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(object && dynamic_cast<Canvas*>(object)) {
|
||||
Canvas &canvas = (Canvas&)*object;
|
||||
canvas.update();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
return bufferRGB;
|
||||
}
|
||||
|
||||
void pCanvas::setGeometry(const Geometry &geometry) {
|
||||
delete[] bufferRGB;
|
||||
bufferRGB = new uint32_t[geometry.width * geometry.height]();
|
||||
pWidget::setGeometry(geometry);
|
||||
update();
|
||||
void pCanvas::setSize(const Size &size) {
|
||||
delete[] data;
|
||||
data = new uint32_t[size.width * size.height];
|
||||
memcpy(data, canvas.state.data, size.width * size.height * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void pCanvas::update() {
|
||||
RECT 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;
|
||||
memset(&bmi, 0, sizeof(BITMAPINFO));
|
||||
|
@ -37,13 +38,14 @@ void pCanvas::update() {
|
|||
|
||||
PAINTSTRUCT 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);
|
||||
InvalidateRect(hwnd, 0, false);
|
||||
}
|
||||
|
||||
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);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas);
|
||||
synchronize();
|
||||
|
@ -51,6 +53,7 @@ void pCanvas::constructor() {
|
|||
|
||||
void pCanvas::destructor() {
|
||||
DestroyWindow(hwnd);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void pCanvas::orphan() {
|
||||
|
|
|
@ -30,6 +30,10 @@ static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPA
|
|||
Label *label = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(!window || !label) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
|
||||
if(msg == WM_GETDLGCODE) {
|
||||
return DLGC_STATIC | DLGC_WANTCHARS;
|
||||
}
|
||||
|
||||
if(msg == WM_ERASEBKGND) {
|
||||
//background is erased during WM_PAINT to prevent flickering
|
||||
return TRUE;
|
||||
|
|
|
@ -34,7 +34,7 @@ string pTextEdit::text() {
|
|||
void pTextEdit::constructor() {
|
||||
hwnd = CreateWindowEx(
|
||||
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
|
||||
);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit);
|
||||
|
|
|
@ -18,5 +18,6 @@ void pViewport::orphan() {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
DipSwitches *dipSwitches = 0;
|
||||
|
||||
DipSwitch::DipSwitch() {
|
||||
append(name, ~0, 0, 5);
|
||||
append(value, ~0, 0);
|
||||
append(name, { ~0, 0 }, 5);
|
||||
append(value, { ~0, 0 }, 0);
|
||||
}
|
||||
|
||||
DipSwitches::DipSwitches() {
|
||||
|
@ -13,10 +13,10 @@ DipSwitches::DipSwitches() {
|
|||
|
||||
append(layout);
|
||||
for(unsigned n = 0; n < 8; n++)
|
||||
layout.append(dip[n], ~0, 0, 5);
|
||||
layout.append(controlLayout, ~0, 0, 5);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(acceptButton, 0, 0);
|
||||
layout.append(dip[n], { ~0, 0 }, 5);
|
||||
layout.append(controlLayout, { ~0, 0 }, 5);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(acceptButton, { 0, 0 }, 0);
|
||||
|
||||
setGeometry({ 128, 128, 400, layout.minimumGeometry().height });
|
||||
windowManager->append(this, "DipSwitches");
|
||||
|
|
|
@ -10,14 +10,14 @@ FileBrowser::FileBrowser() {
|
|||
openButton.setText("Open");
|
||||
|
||||
append(layout);
|
||||
layout.append(pathLayout, ~0, 0, 5);
|
||||
pathLayout.append(pathEdit, ~0, 0, 5);
|
||||
pathLayout.append(pathBrowse, 0, 0, 5);
|
||||
pathLayout.append(pathUp, 0, 0);
|
||||
layout.append(fileList, ~0, ~0, 5);
|
||||
layout.append(controlLayout, ~0, 0);
|
||||
controlLayout.append(filterLabel, ~0, 0, 5);
|
||||
controlLayout.append(openButton, 80, 0);
|
||||
layout.append(pathLayout, { ~0, 0 }, 5);
|
||||
pathLayout.append(pathEdit, { ~0, 0 }, 5);
|
||||
pathLayout.append(pathBrowse, { 0, 0 }, 5);
|
||||
pathLayout.append(pathUp, { 0, 0 });
|
||||
layout.append(fileList, { ~0, ~0 }, 5);
|
||||
layout.append(controlLayout, { ~0, 0 });
|
||||
controlLayout.append(filterLabel, { ~0, 0 }, 5);
|
||||
controlLayout.append(openButton, { 80, 0 });
|
||||
|
||||
pathEdit.onActivate = [&] {
|
||||
string path = pathEdit.text();
|
||||
|
|
|
@ -2,9 +2,9 @@ SlotLoader *slotLoader = 0;
|
|||
|
||||
SlotLoaderPath::SlotLoaderPath() {
|
||||
browse.setText("Browse ...");
|
||||
append(label, 40, 0, 5);
|
||||
append(path, ~0, 0, 5);
|
||||
append(browse, 80, 0);
|
||||
append(label, { 40, 0 }, 5);
|
||||
append(path, { ~0, 0 }, 5);
|
||||
append(browse, { 80, 0 }, 0);
|
||||
}
|
||||
|
||||
SlotLoader::SlotLoader() {
|
||||
|
@ -15,12 +15,12 @@ SlotLoader::SlotLoader() {
|
|||
loadButton.setText("Load");
|
||||
|
||||
append(layout);
|
||||
layout.append(base, ~0, 0, 5);
|
||||
layout.append(slot[0], ~0, 0, 5);
|
||||
layout.append(slot[1], ~0, 0, 5);
|
||||
layout.append(controlLayout, ~0, 0);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(loadButton, 80, 0);
|
||||
layout.append(base, { ~0, 0 }, 5);
|
||||
layout.append(slot[0], { ~0, 0 }, 5);
|
||||
layout.append(slot[1], { ~0, 0 }, 5);
|
||||
layout.append(controlLayout, { ~0, 0 }, 0);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(loadButton, { 80, 0 }, 0);
|
||||
|
||||
setGeometry({ 128, 128, 500, layout.minimumGeometry().height });
|
||||
windowManager->append(this, "SlotLoader");
|
||||
|
|
|
@ -27,7 +27,7 @@ void Application::run() {
|
|||
}
|
||||
|
||||
Application::Application(int argc, char **argv) {
|
||||
title = "bsnes v083.09";
|
||||
title = "bsnes v083.10";
|
||||
|
||||
application = this;
|
||||
quit = false;
|
||||
|
|
|
@ -41,22 +41,22 @@ AdvancedSettings::AdvancedSettings() {
|
|||
if(list[n] == input.default_driver() && config->input.driver == "") inputDriver.setSelection(n);
|
||||
}
|
||||
|
||||
append(title, ~0, 0, 5);
|
||||
append(driverLabel, ~0, 0);
|
||||
append(driverLayout, ~0, 0, 5);
|
||||
driverLayout.append(videoLabel, 0, 0, 5);
|
||||
driverLayout.append(videoDriver, ~0, 0, 5);
|
||||
driverLayout.append(audioLabel, 0, 0, 5);
|
||||
driverLayout.append(audioDriver, ~0, 0, 5);
|
||||
driverLayout.append(inputLabel, 0, 0, 5);
|
||||
driverLayout.append(inputDriver, ~0, 0);
|
||||
append(focusPolicyLabel, ~0, 0);
|
||||
append(focusPolicyLayout, ~0, 0, 5);
|
||||
focusPolicyLayout.append(focusPolicy[0], ~0, 0, 5);
|
||||
focusPolicyLayout.append(focusPolicy[1], ~0, 0, 5);
|
||||
focusPolicyLayout.append(focusPolicy[2], ~0, 0);
|
||||
append(spacer, ~0, ~0);
|
||||
append(aboutLabel, ~0, 0);
|
||||
append(title, { ~0, 0 }, 5);
|
||||
append(driverLabel, { ~0, 0 }, 0);
|
||||
append(driverLayout, { ~0, 0 }, 5);
|
||||
driverLayout.append(videoLabel, { 0, 0 }, 5);
|
||||
driverLayout.append(videoDriver, { ~0, 0 }, 5);
|
||||
driverLayout.append(audioLabel, { 0, 0 }, 5);
|
||||
driverLayout.append(audioDriver, { ~0, 0 }, 5);
|
||||
driverLayout.append(inputLabel, { 0, 0 }, 5);
|
||||
driverLayout.append(inputDriver, { ~0, 0 }, 0);
|
||||
append(focusPolicyLabel, { ~0, 0 }, 0);
|
||||
append(focusPolicyLayout, { ~0, 0 }, 5);
|
||||
focusPolicyLayout.append(focusPolicy[0], { ~0, 0 }, 5);
|
||||
focusPolicyLayout.append(focusPolicy[1], { ~0, 0 }, 5);
|
||||
focusPolicyLayout.append(focusPolicy[2], { ~0, 0 }, 0);
|
||||
append(spacer, { ~0, ~0 }, 0);
|
||||
append(aboutLabel, { ~0, 0 }, 0);
|
||||
|
||||
videoDriver.onChange = [&] {
|
||||
lstring list;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
AudioSettings *audioSettings = 0;
|
||||
|
||||
AudioSlider::AudioSlider() {
|
||||
append(name, 75, 0);
|
||||
append(value, 75, 0);
|
||||
append(slider, ~0, 0);
|
||||
append(name, { 75, 0 });
|
||||
append(value, { 75, 0 });
|
||||
append(slider, { ~0, 0 });
|
||||
}
|
||||
|
||||
unsigned AudioSlider::position() {
|
||||
|
@ -68,20 +68,20 @@ AudioSettings::AudioSettings() {
|
|||
gameBoy.base = 4194304;
|
||||
gameBoy.step = 131;
|
||||
|
||||
append(title, ~0, 0, 5);
|
||||
append(outputLabel, ~0, 0);
|
||||
append(outputLayout, ~0, 0, 5);
|
||||
outputLayout.append(frequencyLabel, 0, 0, 5);
|
||||
outputLayout.append(frequencySelection, ~0, 0, 5);
|
||||
outputLayout.append(latencyLabel, 0, 0, 5);
|
||||
outputLayout.append(latencySelection, ~0, 0, 5);
|
||||
outputLayout.append(resamplerLabel, 0, 0, 5);
|
||||
outputLayout.append(resamplerSelection, ~0, 0);
|
||||
append(volume, ~0, 0, 5);
|
||||
append(frequencyAdjustmentLabel, ~0, 0);
|
||||
append(nes, ~0, 0);
|
||||
append(snes, ~0, 0);
|
||||
append(gameBoy, ~0, 0);
|
||||
append(title, { ~0, 0 }, 5);
|
||||
append(outputLabel, { ~0, 0 }, 0);
|
||||
append(outputLayout, { ~0, 0 }, 5);
|
||||
outputLayout.append(frequencyLabel, { 0, 0 }, 5);
|
||||
outputLayout.append(frequencySelection, { ~0, 0 }, 5);
|
||||
outputLayout.append(latencyLabel, { 0, 0 }, 5);
|
||||
outputLayout.append(latencySelection, { ~0, 0 }, 5);
|
||||
outputLayout.append(resamplerLabel, { 0, 0 }, 5);
|
||||
outputLayout.append(resamplerSelection, { ~0, 0 }, 0);
|
||||
append(volume, { ~0, 0 }, 5);
|
||||
append(frequencyAdjustmentLabel, { ~0, 0 }, 0);
|
||||
append(nes, { ~0, 0 }, 0);
|
||||
append(snes, { ~0, 0 }, 0);
|
||||
append(gameBoy, { ~0, 0 }, 0);
|
||||
|
||||
frequencySelection.setSelection(
|
||||
config->audio.frequency == 32000 ? 0 :
|
||||
|
|
|
@ -15,18 +15,18 @@ InputSettings::InputSettings() : activeInput(0) {
|
|||
}
|
||||
primaryChange();
|
||||
|
||||
append(title, ~0, 0, 5);
|
||||
append(selectionLayout, ~0, 0, 5);
|
||||
selectionLayout.append(primary, ~0, 0, 5);
|
||||
selectionLayout.append(secondary, ~0, 0, 5);
|
||||
selectionLayout.append(tertiary, ~0, 0);
|
||||
append(inputList, ~0, ~0, 5);
|
||||
append(controlLayout, ~0, 0);
|
||||
controlLayout.append(assignPrimary, 100, 0, 5);
|
||||
controlLayout.append(assignSecondary, 100, 0, 5);
|
||||
controlLayout.append(assignTertiary, 100, 0, 5);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(clearButton, 80, 0);
|
||||
append(title, { ~0, 0 }, 5);
|
||||
append(selectionLayout, { ~0, 0 }, 5);
|
||||
selectionLayout.append(primary, { ~0, 0 }, 5);
|
||||
selectionLayout.append(secondary, { ~0, 0 }, 5);
|
||||
selectionLayout.append(tertiary, { ~0, 0 }, 0);
|
||||
append(inputList, { ~0, ~0 }, 5);
|
||||
append(controlLayout, { ~0, 0 }, 0);
|
||||
controlLayout.append(assignPrimary, { 100, 0 }, 5);
|
||||
controlLayout.append(assignSecondary, { 100, 0 }, 5);
|
||||
controlLayout.append(assignTertiary, { 100, 0 }, 5);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(clearButton, { 80, 0 }, 0);
|
||||
|
||||
primary.onChange = { &InputSettings::primaryChange, this };
|
||||
secondary.onChange = { &InputSettings::secondaryChange, this };
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#include "advanced.cpp"
|
||||
SettingsWindow *settingsWindow = 0;
|
||||
|
||||
void SettingsLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) {
|
||||
layout.append(sizable, width, height, spacing);
|
||||
void SettingsLayout::append(Sizable &sizable, const Size &size, unsigned spacing) {
|
||||
layout.append(sizable, size, spacing);
|
||||
}
|
||||
|
||||
SettingsLayout::SettingsLayout() {
|
||||
setMargin(5);
|
||||
HorizontalLayout::append(spacer, 120, ~0, 5);
|
||||
HorizontalLayout::append(layout, ~0, ~0);
|
||||
HorizontalLayout::append(spacer, { 120, ~0 }, 5);
|
||||
HorizontalLayout::append(layout, { ~0, ~0 }, 0);
|
||||
}
|
||||
|
||||
SettingsWindow::SettingsWindow() {
|
||||
|
@ -34,7 +34,7 @@ SettingsWindow::SettingsWindow() {
|
|||
advancedSettings = new AdvancedSettings;
|
||||
|
||||
append(layout);
|
||||
layout.append(panelList, 120, ~0, 5);
|
||||
layout.append(panelList, { 120, ~0 }, 5);
|
||||
append(*videoSettings);
|
||||
append(*audioSettings);
|
||||
append(*inputSettings);
|
||||
|
|
|
@ -2,7 +2,7 @@ struct SettingsLayout : HorizontalLayout {
|
|||
Widget spacer;
|
||||
VerticalLayout layout;
|
||||
|
||||
void append(Sizable &widget, unsigned width, unsigned height, unsigned spacing = 0);
|
||||
void append(Sizable &widget, const Size &size, unsigned spacing = 0);
|
||||
SettingsLayout();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
VideoSettings *videoSettings = 0;
|
||||
|
||||
VideoSlider::VideoSlider() {
|
||||
append(name, 75, 0);
|
||||
append(value, 75, 0);
|
||||
append(slider, ~0, 0);
|
||||
append(name, { 75, 0 });
|
||||
append(value, { 75, 0 });
|
||||
append(slider, { ~0, 0 });
|
||||
}
|
||||
|
||||
VideoSettings::VideoSettings() {
|
||||
|
@ -36,24 +36,24 @@ VideoSettings::VideoSettings() {
|
|||
compositor[2].setText("Always");
|
||||
RadioBox::group(compositor[0], compositor[1], compositor[2]);
|
||||
|
||||
append(title, ~0, 0, 5);
|
||||
append(colorAdjustment, ~0, 0);
|
||||
append(brightness, ~0, 0);
|
||||
append(contrast, ~0, 0);
|
||||
append(gamma, ~0, 0, 5);
|
||||
append(overscanAdjustment, ~0, 0);
|
||||
append(overscanHorizontal, ~0, 0);
|
||||
append(overscanVertical, ~0, 0, 5);
|
||||
append(fullScreenMode, ~0, 0);
|
||||
append(fullScreenLayout, ~0, 0, 5);
|
||||
fullScreenLayout.append(fullScreen[0], ~0, 0, 5);
|
||||
fullScreenLayout.append(fullScreen[1], ~0, 0, 5);
|
||||
fullScreenLayout.append(fullScreen[2], ~0, 0);
|
||||
append(compositorLabel, ~0, 0);
|
||||
append(compositorLayout, ~0, 0);
|
||||
compositorLayout.append(compositor[0], ~0, 0, 5);
|
||||
compositorLayout.append(compositor[1], ~0, 0, 5);
|
||||
compositorLayout.append(compositor[2], ~0, 0);
|
||||
append(title, { ~0, 0 }, 5);
|
||||
append(colorAdjustment, { ~0, 0 }, 0);
|
||||
append(brightness, { ~0, 0 }, 0);
|
||||
append(contrast, { ~0, 0 }, 0);
|
||||
append(gamma, { ~0, 0 }, 5);
|
||||
append(overscanAdjustment, { ~0, 0 }, 0);
|
||||
append(overscanHorizontal, { ~0, 0 }, 0);
|
||||
append(overscanVertical, { ~0, 0 }, 5);
|
||||
append(fullScreenMode, { ~0, 0 }, 0);
|
||||
append(fullScreenLayout, { ~0, 0 }, 5);
|
||||
fullScreenLayout.append(fullScreen[0], { ~0, 0 }, 5);
|
||||
fullScreenLayout.append(fullScreen[1], { ~0, 0 }, 5);
|
||||
fullScreenLayout.append(fullScreen[2], { ~0, 0 }, 0);
|
||||
append(compositorLabel, { ~0, 0 }, 0);
|
||||
append(compositorLayout, { ~0, 0 }, 0);
|
||||
compositorLayout.append(compositor[0], { ~0, 0 }, 5);
|
||||
compositorLayout.append(compositor[1], { ~0, 0 }, 5);
|
||||
compositorLayout.append(compositor[2], { ~0, 0 }, 0);
|
||||
|
||||
brightness.slider.setPosition(config->video.brightness);
|
||||
contrast.slider.setPosition(config->video.contrast);
|
||||
|
@ -95,9 +95,6 @@ void VideoSettings::synchronize() {
|
|||
config->video.gamma = gamma.slider.position();
|
||||
config->video.maskOverscanHorizontal = overscanHorizontal.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, "%" });
|
||||
contrast.value.setText({ config->video.contrast, "%" });
|
||||
|
|
|
@ -11,12 +11,12 @@ CheatDatabase::CheatDatabase() {
|
|||
acceptButton.setText("Add Codes");
|
||||
|
||||
append(layout);
|
||||
layout.append(cheatList, ~0, ~0, 5);
|
||||
layout.append(controlLayout, ~0, 0);
|
||||
controlLayout.append(selectAllButton, 100, 0, 5);
|
||||
controlLayout.append(unselectAllButton, 100, 0);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(acceptButton, 80, 0);
|
||||
layout.append(cheatList, { ~0, ~0 }, 5);
|
||||
layout.append(controlLayout, { ~0, 0 }, 0);
|
||||
controlLayout.append(selectAllButton, { 100, 0 }, 5);
|
||||
controlLayout.append(unselectAllButton, { 100, 0 }, 0);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(acceptButton, { 80, 0 }, 0);
|
||||
|
||||
selectAllButton.onTick = [&] {
|
||||
for(unsigned n = 0; n < cheatCode.size(); n++) cheatList.setChecked(n, true);
|
||||
|
|
|
@ -16,18 +16,18 @@ CheatEditor::CheatEditor() {
|
|||
|
||||
append(layout);
|
||||
layout.setMargin(5);
|
||||
layout.append(cheatList, ~0, ~0, 5);
|
||||
layout.append(codeLayout, ~0, 0, 5);
|
||||
codeLayout.append(codeLabel, 80, 0);
|
||||
codeLayout.append(codeEdit, ~0, 0);
|
||||
layout.append(descLayout, ~0, 0, 5);
|
||||
descLayout.append(descLabel, 80, 0);
|
||||
descLayout.append(descEdit, ~0, 0);
|
||||
layout.append(controlLayout, ~0, 0);
|
||||
controlLayout.append(findButton, 100, 0);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(clearAllButton, 80, 0, 5);
|
||||
controlLayout.append(clearButton, 80, 0);
|
||||
layout.append(cheatList, { ~0, ~0 }, 5);
|
||||
layout.append(codeLayout, { ~0, 0 }, 5);
|
||||
codeLayout.append(codeLabel, { 80, 0 }, 0);
|
||||
codeLayout.append(codeEdit, { ~0, 0 }, 0);
|
||||
layout.append(descLayout, { ~0, 0 }, 5);
|
||||
descLayout.append(descLabel, { 80, 0 }, 0);
|
||||
descLayout.append(descEdit, { ~0, 0 }, 0);
|
||||
layout.append(controlLayout, { ~0, 0 }, 0);
|
||||
controlLayout.append(findButton, { 100, 0 }, 0);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(clearAllButton, { 80, 0 }, 5);
|
||||
controlLayout.append(clearButton, { 80, 0 }, 0);
|
||||
|
||||
for(unsigned n = 0; n < 128; n++) cheatList.append("", "", "");
|
||||
updateUI();
|
||||
|
|
|
@ -14,15 +14,15 @@ StateManager::StateManager() {
|
|||
|
||||
append(layout);
|
||||
layout.setMargin(5);
|
||||
layout.append(stateList, ~0, ~0, 5);
|
||||
layout.append(descLayout, ~0, 0, 5);
|
||||
descLayout.append(descLabel, 0, 0, 5);
|
||||
descLayout.append(descEdit, ~0, 0);
|
||||
layout.append(controlLayout, ~0, 0);
|
||||
controlLayout.append(spacer, ~0, 0);
|
||||
controlLayout.append(loadButton, 80, 0, 5);
|
||||
controlLayout.append(saveButton, 80, 0, 5);
|
||||
controlLayout.append(eraseButton, 80, 0);
|
||||
layout.append(stateList, { ~0, ~0 }, 5);
|
||||
layout.append(descLayout, { ~0, 0 }, 5);
|
||||
descLayout.append(descLabel, { 0, 0 }, 5);
|
||||
descLayout.append(descEdit, { ~0, 0 }, 0);
|
||||
layout.append(controlLayout, { ~0, 0 }, 0);
|
||||
controlLayout.append(spacer, { ~0, 0 }, 0);
|
||||
controlLayout.append(loadButton, { 80, 0 }, 5);
|
||||
controlLayout.append(saveButton, { 80, 0 }, 5);
|
||||
controlLayout.append(eraseButton, { 80, 0 }, 0);
|
||||
|
||||
for(unsigned n = 0; n < 32; n++) stateList.append(decimal<2>(n + 1), "(empty)");
|
||||
stateList.autoSizeColumns();
|
||||
|
|
|
@ -47,6 +47,7 @@ void Utility::resizeMainWindow(bool shrink) {
|
|||
unsigned width = geometry.width, height = geometry.height;
|
||||
|
||||
switch(interface->mode()) {
|
||||
case Interface::Mode::None: return;
|
||||
case Interface::Mode::NES: width = 256, height = 240; break;
|
||||
case Interface::Mode::SNES: width = 256, height = 240; break;
|
||||
case Interface::Mode::GameBoy: width = 160, height = 144; break;
|
||||
|
|
Loading…
Reference in New Issue