diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 13a9295c..739c5684 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -static const char Version[] = "088.02"; +static const char Version[] = "088.03"; #include #include @@ -19,6 +19,7 @@ static const char Version[] = "088.02"; #include #include #include +#include using namespace nall; //debugging function hook: @@ -39,8 +40,8 @@ template struct hook { hook(const hook &hook) { callback = hook.callback; } hook(void *function) { callback = function; } hook(R (*function)(P...)) { callback = function; } - template hook(R (C::*function)(P...), C *object) { callback = { function, object }; } - template hook(R (C::*function)(P...) const, C *object) { callback = { function, object }; } + template hook(R (C::*function)(P...), C *object) { callback = {function, object}; } + template hook(R (C::*function)(P...) const, C *object) { callback = {function, object}; } template hook(const L& function) { callback = function; } hook& operator=(const hook& hook) { callback = hook.callback; return *this; } diff --git a/bsnes/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp index 18fceae8..994cd0af 100755 --- a/bsnes/gb/cartridge/cartridge.cpp +++ b/bsnes/gb/cartridge/cartridge.cpp @@ -14,10 +14,10 @@ namespace GameBoy { #include "serialization.cpp" Cartridge cartridge; -void Cartridge::load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size) { - if(size == 0) size = 32768; - romdata = allocate(romsize = size, 0xff); - if(data) memcpy(romdata, data, size); +void Cartridge::load(System::Revision revision, const string &markup, const stream &memory) { + romsize = memory.size() ? memory.size() : 32768u; + romdata = allocate(romsize, 0xff); + memory.read(romdata, memory.size()); information.markup = markup; information.mapper = Mapper::Unknown; @@ -49,14 +49,14 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true"; switch(information.mapper) { default: - case Mapper::MBC0: mapper = &mbc0; break; - case Mapper::MBC1: mapper = &mbc1; break; - case Mapper::MBC2: mapper = &mbc2; break; - case Mapper::MBC3: mapper = &mbc3; break; - case Mapper::MBC5: mapper = &mbc5; break; - case Mapper::MMM01: mapper = &mmm01; break; - case Mapper::HuC1: mapper = &huc1; break; - case Mapper::HuC3: mapper = &huc3; break; + case Mapper::MBC0: mapper = &mbc0; break; + case Mapper::MBC1: mapper = &mbc1; break; + case Mapper::MBC2: mapper = &mbc2; break; + case Mapper::MBC3: mapper = &mbc3; break; + case Mapper::MBC5: mapper = &mbc5; break; + case Mapper::MMM01: mapper = &mmm01; break; + case Mapper::HuC1: mapper = &huc1; break; + case Mapper::HuC3: mapper = &huc3; break; } ramdata = new uint8_t[ramsize = information.ramsize](); diff --git a/bsnes/gb/cartridge/cartridge.hpp b/bsnes/gb/cartridge/cartridge.hpp index b505fcf0..93574690 100755 --- a/bsnes/gb/cartridge/cartridge.hpp +++ b/bsnes/gb/cartridge/cartridge.hpp @@ -45,7 +45,7 @@ struct Cartridge : MMIO, property { MMIO *mapper; bool bootrom_enable; - void load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size); + void load(System::Revision revision, const string &markup, const stream &memory); void unload(); uint8 rom_read(unsigned addr); diff --git a/bsnes/gb/interface/interface.cpp b/bsnes/gb/interface/interface.cpp index 925c2831..248a988d 100755 --- a/bsnes/gb/interface/interface.cpp +++ b/bsnes/gb/interface/interface.cpp @@ -10,7 +10,12 @@ void Interface::lcdScanline() { void Interface::joypWrite(bool p15, bool p14) { } -void Interface::videoRefresh(const uint16_t *data) { +uint32_t Interface::videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue) { + red >>= 8, green >>= 8, blue >>= 8; + return red << 16 | green << 8 | blue << 0; +} + +void Interface::videoRefresh(const uint32_t *data) { } void Interface::audioSample(int16_t center, int16_t left, int16_t right) { diff --git a/bsnes/gb/interface/interface.hpp b/bsnes/gb/interface/interface.hpp index 918e606b..25af439d 100755 --- a/bsnes/gb/interface/interface.hpp +++ b/bsnes/gb/interface/interface.hpp @@ -2,7 +2,8 @@ struct Interface { virtual void lcdScanline(); virtual void joypWrite(bool p15, bool p14); - virtual void videoRefresh(const uint16_t *data); + virtual uint32_t videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue); + virtual void videoRefresh(const uint32_t *data); virtual void audioSample(int16_t center, int16_t left, int16_t right); virtual bool inputPoll(unsigned id); diff --git a/bsnes/gb/ppu/cgb.cpp b/bsnes/gb/ppu/cgb.cpp index 7964c9e5..d95939e0 100755 --- a/bsnes/gb/ppu/cgb.cpp +++ b/bsnes/gb/ppu/cgb.cpp @@ -12,8 +12,8 @@ void PPU::cgb_render() { if(status.ob_enable) cgb_render_ob(); } - uint16 *output = screen + status.ly * 160; - for(unsigned n = 0; n < 160; n++) output[n] = line[n]; + uint32 *output = screen + status.ly * 160; + for(unsigned n = 0; n < 160; n++) output[n] = video.palette[line[n]]; interface->lcdScanline(); } diff --git a/bsnes/gb/ppu/dmg.cpp b/bsnes/gb/ppu/dmg.cpp index b60a83b9..9deaab86 100755 --- a/bsnes/gb/ppu/dmg.cpp +++ b/bsnes/gb/ppu/dmg.cpp @@ -12,8 +12,8 @@ void PPU::dmg_render() { if(status.ob_enable) dmg_render_ob(); } - uint16 *output = screen + status.ly * 160; - for(unsigned n = 0; n < 160; n++) output[n] = line[n]; + uint32 *output = screen + status.ly * 160; + for(unsigned n = 0; n < 160; n++) output[n] = video.palette[line[n]]; interface->lcdScanline(); } diff --git a/bsnes/gb/ppu/ppu.hpp b/bsnes/gb/ppu/ppu.hpp index eec8b4b8..44e3581a 100755 --- a/bsnes/gb/ppu/ppu.hpp +++ b/bsnes/gb/ppu/ppu.hpp @@ -49,7 +49,7 @@ struct PPU : Thread, MMIO { uint8 obpi; } status; - uint16 screen[160 * 144]; + uint32 screen[160 * 144]; uint16 line[160]; struct Origin { enum : unsigned { None, BG, BGP, OB }; }; uint8 origin[160]; diff --git a/bsnes/gb/video/video.cpp b/bsnes/gb/video/video.cpp index 541bad1f..a032e2f4 100755 --- a/bsnes/gb/video/video.cpp +++ b/bsnes/gb/video/video.cpp @@ -5,20 +5,34 @@ namespace GameBoy { Video video; -unsigned Video::palette_dmg(unsigned color) const { - unsigned R = monochrome[color][0] * 1023.0; - unsigned G = monochrome[color][1] * 1023.0; - unsigned B = monochrome[color][2] * 1023.0; +void Video::generate_palette() { + if(system.dmg()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_dmg(n); + if(system.sgb()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_sgb(n); + if(system.cgb()) for(unsigned n = 0; n < (1 << 15); n++) palette[n] = palette_cgb(n); +} - return (R << 20) + (G << 10) + (B << 0); +Video::Video() { + palette = new unsigned[1 << 15](); +} + +Video::~Video() { + delete[] palette; +} + +unsigned Video::palette_dmg(unsigned color) const { + unsigned R = monochrome[color][0] * 65535.0; + unsigned G = monochrome[color][1] * 65535.0; + unsigned B = monochrome[color][2] * 65535.0; + + return interface->videoColor(color, R, G, B); } unsigned Video::palette_sgb(unsigned color) const { - unsigned R = (3 - color) * 341; - unsigned G = (3 - color) * 341; - unsigned B = (3 - color) * 341; + unsigned R = (3 - color) * 21845; + unsigned G = (3 - color) * 21845; + unsigned B = (3 - color) * 21845; - return (R << 20) + (G << 10) + (B << 0); + return interface->videoColor(color, R, G, B); } unsigned Video::palette_cgb(unsigned color) const { @@ -34,42 +48,11 @@ unsigned Video::palette_cgb(unsigned color) const { G = min(960, G); B = min(960, B); - return (R << 20) + (G << 10) + (B << 0); -} + R = R << 6 | R >> 4; + G = G << 6 | G >> 4; + B = B << 6 | B >> 4; -void Video::generate(Format format) { - if(system.dmg()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_dmg(n); - if(system.sgb()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_sgb(n); - if(system.cgb()) for(unsigned n = 0; n < (1 << 15); n++) palette[n] = palette_cgb(n); - - if(format == Format::RGB24) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); - } - } - - if(format == Format::RGB16) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); - } - } - - if(format == Format::RGB15) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); - } - } -} - -Video::Video() { - palette = new unsigned[1 << 15](); -} - -Video::~Video() { - delete[] palette; + return interface->videoColor(color, R, G, B); } const double Video::monochrome[4][3] = { diff --git a/bsnes/gb/video/video.hpp b/bsnes/gb/video/video.hpp index 131b2868..bb15349e 100755 --- a/bsnes/gb/video/video.hpp +++ b/bsnes/gb/video/video.hpp @@ -1,17 +1,15 @@ struct Video { - enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; - unsigned *palette; + uint32_t *palette; + void generate_palette(); - unsigned palette_dmg(unsigned color) const; - unsigned palette_sgb(unsigned color) const; - unsigned palette_cgb(unsigned color) const; - - void generate(Format format); Video(); ~Video(); private: static const double monochrome[4][3]; + uint32_t palette_dmg(unsigned color) const; + uint32_t palette_sgb(unsigned color) const; + uint32_t palette_cgb(unsigned color) const; }; extern Video video; diff --git a/bsnes/gba/interface/interface.cpp b/bsnes/gba/interface/interface.cpp index 6df86f1e..7857aece 100755 --- a/bsnes/gba/interface/interface.cpp +++ b/bsnes/gba/interface/interface.cpp @@ -4,7 +4,12 @@ namespace GameBoyAdvance { Interface *interface = nullptr; -void Interface::videoRefresh(const uint16_t *data) { +uint32_t Interface::videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue) { + red >>= 8, green >>= 8, blue >>= 8; + return red << 16 | green << 8 | blue << 0; +} + +void Interface::videoRefresh(const uint32_t *data) { } void Interface::audioSample(int16_t lsample, int16_t rsample) { diff --git a/bsnes/gba/interface/interface.hpp b/bsnes/gba/interface/interface.hpp index d33517a5..46a957d4 100755 --- a/bsnes/gba/interface/interface.hpp +++ b/bsnes/gba/interface/interface.hpp @@ -1,5 +1,6 @@ struct Interface { - virtual void videoRefresh(const uint16_t *data); + virtual uint32_t videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue); + virtual void videoRefresh(const uint32_t *data); virtual void audioSample(int16_t lsample, int16_t rsample); virtual bool inputPoll(unsigned id); diff --git a/bsnes/gba/ppu/ppu.cpp b/bsnes/gba/ppu/ppu.cpp index e3c41ca4..aaba4ef0 100755 --- a/bsnes/gba/ppu/ppu.cpp +++ b/bsnes/gba/ppu/ppu.cpp @@ -153,7 +153,7 @@ void PPU::frame() { } PPU::PPU() { - output = new uint16[240 * 160]; + output = new uint32[240 * 160]; blur = new uint16[240 * 160]; regs.bg[0].id = BG0; diff --git a/bsnes/gba/ppu/ppu.hpp b/bsnes/gba/ppu/ppu.hpp index c4573de8..7840c4dc 100755 --- a/bsnes/gba/ppu/ppu.hpp +++ b/bsnes/gba/ppu/ppu.hpp @@ -3,7 +3,7 @@ struct PPU : Thread, MMIO { uint16 pram[512]; #include "registers.hpp" #include "state.hpp" - uint16 *output; + uint32 *output; uint16 *blur; static void Enter(); diff --git a/bsnes/gba/ppu/screen.cpp b/bsnes/gba/ppu/screen.cpp index 09b2934e..0124df02 100755 --- a/bsnes/gba/ppu/screen.cpp +++ b/bsnes/gba/ppu/screen.cpp @@ -1,14 +1,14 @@ void PPU::render_forceblank() { - uint16 *line = output + regs.vcounter * 240; + uint32 *line = output + regs.vcounter * 240; uint16 *last = blur + regs.vcounter * 240; for(unsigned x = 0; x < 240; x++) { - line[x] = (0x7fff + last[x] - ((0x7fff ^ last[x]) & 0x0421)) >> 1; + line[x] = video.palette[(0x7fff + last[x] - ((0x7fff ^ last[x]) & 0x0421)) >> 1]; last[x] = 0x7fff; } } void PPU::render_screen() { - uint16 *line = output + regs.vcounter * 240; + uint32 *line = output + regs.vcounter * 240; uint16 *last = blur + regs.vcounter * 240; if(regs.bg[0].control.mosaic) render_mosaic_background(BG0); @@ -59,7 +59,7 @@ void PPU::render_screen() { } //output pixel; blend with previous pixel to simulate GBA LCD blur - line[x] = (color + last[x] - ((color ^ last[x]) & 0x0421)) >> 1; + line[x] = video.palette[(color + last[x] - ((color ^ last[x]) & 0x0421)) >> 1]; last[x] = color; } } diff --git a/bsnes/gba/video/video.cpp b/bsnes/gba/video/video.cpp index 7191dd85..5b0be7c0 100755 --- a/bsnes/gba/video/video.cpp +++ b/bsnes/gba/video/video.cpp @@ -4,40 +4,17 @@ namespace GameBoyAdvance { Video video; -unsigned Video::color(unsigned color) const { - uint5 b = color >> 10; - uint5 g = color >> 5; - uint5 r = color >> 0; +void Video::generate_palette() { + for(unsigned color = 0; color < (1 << 15); color++) { + uint5 b = color >> 10; + uint5 g = color >> 5; + uint5 r = color >> 0; - uint10 R = (r << 5) | (r << 0); - uint10 G = (g << 5) | (g << 0); - uint10 B = (b << 5) | (b << 0); + uint16 R = r << 11 | r << 6 | r << 1 | r >> 4; + uint16 G = g << 11 | g << 6 | g << 1 | g >> 4; + uint16 B = b << 11 | b << 6 | b << 1 | b >> 4; - return (R << 20) | (G << 10) | (B << 0); -} - -void Video::generate(Format format) { - for(unsigned n = 0; n < (1 << 15); n++) palette[n] = color(n); - - if(format == Format::RGB24) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); - } - } - - if(format == Format::RGB16) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); - } - } - - if(format == Format::RGB15) { - for(unsigned n = 0; n < (1 << 15); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); - } + palette[color] = interface->videoColor(color, R, G, B); } } diff --git a/bsnes/gba/video/video.hpp b/bsnes/gba/video/video.hpp index 5856930b..15004b36 100755 --- a/bsnes/gba/video/video.hpp +++ b/bsnes/gba/video/video.hpp @@ -1,9 +1,7 @@ struct Video { - enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; unsigned *palette; + void generate_palette(); - unsigned color(unsigned color) const; - void generate(Format format); Video(); ~Video(); }; diff --git a/bsnes/nall/array.hpp b/bsnes/nall/array.hpp deleted file mode 100755 index a38355ba..00000000 --- a/bsnes/nall/array.hpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef NALL_ARRAY_HPP -#define NALL_ARRAY_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nall { - -template struct array { - struct exception_out_of_bounds{}; - -protected: - T *pool; - unsigned poolsize, objectsize; - -public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) free(pool); - pool = nullptr; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned newsize) { - if(newsize == poolsize) return; - - pool = (T*)realloc(pool, newsize * sizeof(T)); - poolsize = newsize; - objectsize = min(objectsize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2 - objectsize = newsize; - } - - T* get(unsigned minsize = 0) { - if(minsize > objectsize) resize(minsize); - return pool; - } - - void append(const T data) { - operator()(objectsize) = data; - } - - void append(const T data[], unsigned length) { - for(unsigned n = 0; n < length; n++) operator()(objectsize) = data[n]; - } - - void remove() { - if(size() > 0) resize(size - 1); //remove last element only - } - - void remove(unsigned index, unsigned count = 1) { - for(unsigned i = index; count + i < objectsize; i++) { - pool[i] = pool[count + i]; - } - if(count + index >= objectsize) resize(index); //every element >= index was removed - else resize(objectsize - count); - } - - void sort() { - nall::sort(pool, objectsize); - } - - template void sort(const Comparator &lessthan) { - nall::sort(pool, objectsize, lessthan); - } - - optional find(const T data) { - for(unsigned n = 0; n < size(); n++) if(pool[n] == data) return { true, n }; - return { false, 0u }; - } - - void clear() { - memset(pool, 0, objectsize * sizeof(T)); - } - - array() : pool(nullptr), poolsize(0), objectsize(0) { - } - - array(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { - for(auto &data : list) append(data); - } - - ~array() { - reset(); - } - - //copy - array& operator=(const array &source) { - if(pool) free(pool); - objectsize = source.objectsize; - poolsize = source.poolsize; - pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size, - memcpy(pool, source.pool, sizeof(T) * objectsize); //... but only copy used pool objects - return *this; - } - - array(const array &source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(source); - } - - //move - array& operator=(array &&source) { - if(pool) free(pool); - pool = source.pool; - poolsize = source.poolsize; - objectsize = source.objectsize; - source.pool = nullptr; - source.reset(); - return *this; - } - - array(array &&source) : pool(nullptr), poolsize(0), objectsize(0) { - operator=(std::move(source)); - } - - //access - inline T& operator[](unsigned position) { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[position]; - } - - inline const T& operator[](unsigned position) const { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[position]; - } - - inline T& operator()(unsigned position) { - if(position >= objectsize) resize(position + 1); - return pool[position]; - } - - inline const T& operator()(unsigned position, const T& data) { - if(position >= objectsize) return data; - return pool[position]; - } - - //iteration - T* begin() { return &pool[0]; } - T* end() { return &pool[objectsize]; } - const T* begin() const { return &pool[0]; } - const T* end() const { return &pool[objectsize]; } -}; - -} - -#endif diff --git a/bsnes/nall/bit.hpp b/bsnes/nall/bit.hpp index 78b47c1e..63403eb0 100755 --- a/bsnes/nall/bit.hpp +++ b/bsnes/nall/bit.hpp @@ -1,6 +1,8 @@ #ifndef NALL_BIT_HPP #define NALL_BIT_HPP +#include + namespace nall { template inline uintmax_t uclamp(const uintmax_t x) { diff --git a/bsnes/nall/bitarray.hpp b/bsnes/nall/bitarray.hpp deleted file mode 100755 index 849690f9..00000000 --- a/bsnes/nall/bitarray.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef NALL_BITARRAY_HPP -#define NALL_BITARRAY_HPP - -#include - -//statically-sized bit array -//no bounds-checking on read/write -//packed into uint8_t array (8 bits per byte) - -namespace nall { - -struct bitarray { - uint8_t *pool; - unsigned poolsize; - - uint8_t* data() { return pool; } - const uint8_t* data() const { return pool; } - unsigned size() const { return poolsize; } - unsigned bytesize() const { return (poolsize >> 3) + ((poolsize & 7) > 0); } - - void reset() { - if(pool) free(pool); - pool = nullptr; - poolsize = 0u; - } - - void resize(unsigned allocsize) { - if(allocsize == poolsize) return; - pool = (uint8_t*)realloc(pool, allocsize); - poolsize = allocsize; - } - - bool operator[](unsigned offset) const { - return pool[offset >> 3] & (0x80 >> (offset & 7)); - } - - void set() { - memset(pool, 0xff, (poolsize >> 3) + ((poolsize & 7) > 0)); - } - - void set(unsigned offset) { - pool[offset >> 3] |= 0x80 >> (offset & 7); - } - - void clear() { - memset(pool, 0, (poolsize >> 3) + ((poolsize & 7) > 0)); - } - - void clear(unsigned offset) { - pool[offset >> 3] &=~0x80 >> (offset & 7); - } - - void set(unsigned offset, bool data) { - data ? set(offset) : clear(offset); - } - - struct bit { - bitarray &array; - unsigned offset; - operator bool() const { return const_cast(array)[offset]; } - bit& operator=(bool data) { array.set(offset, data); return *this; } - bit& operator=(const bit& data) { return operator=((bool)data); } - bit(bitarray &array, unsigned offset) : array(array), offset(offset) {} - }; - - bit operator[](unsigned offset) { - return bit(*this, offset); - } - - bitarray() : pool(nullptr), poolsize(0u) {} - bitarray(unsigned allocsize) { - pool = (uint8_t*)malloc((allocsize >> 3) + ((allocsize & 7) > 0)); - poolsize = allocsize; - } -}; - -} - -#endif diff --git a/bsnes/nall/file.hpp b/bsnes/nall/file.hpp index 2c26ce56..83e2c992 100755 --- a/bsnes/nall/file.hpp +++ b/bsnes/nall/file.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace nall { inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) { @@ -16,25 +17,19 @@ namespace nall { #endif } - class file { - public: + struct file { enum class mode : unsigned { read, write, readwrite, writeread }; enum class index : unsigned { absolute, relative }; enum class time : unsigned { create, modify, access }; - static bool read(const string &filename, uint8_t *&data, unsigned &size) { - data = 0; + static vector read(const string &filename) { + vector memory; file fp; - if(fp.open(filename, mode::read) == false) return false; - size = fp.size(); - data = new uint8_t[size]; - fp.read(data, size); - fp.close(); - return true; - } - - static bool read(const string &filename, const uint8_t *&data, unsigned &size) { - return file::read(filename, (uint8_t*&)data, size); + if(fp.open(filename, mode::read)) { + memory.resize(fp.size()); + fp.read(memory.data(), memory.size()); + } + return memory; } static bool write(const string &filename, const uint8_t *data, unsigned size) { diff --git a/bsnes/nall/gzip.hpp b/bsnes/nall/gzip.hpp index fa0aaad1..a72a3faf 100755 --- a/bsnes/nall/gzip.hpp +++ b/bsnes/nall/gzip.hpp @@ -19,12 +19,10 @@ struct gzip { }; bool gzip::decompress(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - bool result = decompress(data, size); - delete[] data; - return result; + if(auto memory = file::read(filename)) { + return decompress(memory.data(), memory.size()); + } + return false; } bool gzip::decompress(const uint8_t *data, unsigned size) { diff --git a/bsnes/nall/ips.hpp b/bsnes/nall/ips.hpp index 3071d038..473d74c5 100755 --- a/bsnes/nall/ips.hpp +++ b/bsnes/nall/ips.hpp @@ -11,8 +11,6 @@ struct ips { inline bool apply(); inline void source(const uint8_t *data, unsigned size); inline void modify(const uint8_t *data, unsigned size); - inline bool source(const string &filename); - inline bool modify(const string &filename); inline ips(); inline ~ips(); @@ -88,14 +86,6 @@ void ips::modify(const uint8_t *data, unsigned size) { modifyData = data, modifySize = size; } -bool ips::source(const string &filename) { - return file::read(filename, sourceData, sourceSize); -} - -bool ips::modify(const string &filename) { - return file::read(filename, modifyData, modifySize); -} - ips::ips() : data(nullptr), sourceData(nullptr), modifyData(nullptr) { } diff --git a/bsnes/nall/png.hpp b/bsnes/nall/png.hpp index 4b474724..f5ebaab4 100755 --- a/bsnes/nall/png.hpp +++ b/bsnes/nall/png.hpp @@ -58,12 +58,10 @@ protected: }; bool png::decode(const string &filename) { - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) return false; - bool result = decode(data, size); - delete[] data; - return result; + if(auto memory = file::read(filename)) { + return decode(memory.data(), memory.size()); + } + return false; } bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { diff --git a/bsnes/nall/stream/auto.hpp b/bsnes/nall/stream/auto.hpp index 148c7fd4..d1b6e2ba 100755 --- a/bsnes/nall/stream/auto.hpp +++ b/bsnes/nall/stream/auto.hpp @@ -1,4 +1,5 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_AUTO_HPP +#define NALL_STREAM_AUTO_HPP namespace nall { diff --git a/bsnes/nall/stream/file.hpp b/bsnes/nall/stream/file.hpp index 55521f07..3fc45d33 100755 --- a/bsnes/nall/stream/file.hpp +++ b/bsnes/nall/stream/file.hpp @@ -1,21 +1,24 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_FILE_HPP +#define NALL_STREAM_FILE_HPP + +#include namespace nall { struct filestream : stream { - inline bool seekable() const { return true; } - inline bool readable() const { return true; } - inline bool writable() const { return pwritable; } - inline bool randomaccess() const { return false; } + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return false; } - inline unsigned size() const { return pfile.size(); } - inline unsigned offset() const { return pfile.offset(); } - inline void seek(unsigned offset) const { pfile.seek(offset); } + unsigned size() const { return pfile.size(); } + unsigned offset() const { return pfile.offset(); } + void seek(unsigned offset) const { pfile.seek(offset); } - inline uint8_t read() const { return pfile.read(); } - inline void write(uint8_t data) const { pfile.write(data); } + uint8_t read() const { return pfile.read(); } + void write(uint8_t data) const { pfile.write(data); } - inline filestream(const string &filename) { + filestream(const string &filename) { pfile.open(filename, file::mode::readwrite); pwritable = pfile.open(); if(!pwritable) pfile.open(filename, file::mode::read); diff --git a/bsnes/nall/stream/gzip.hpp b/bsnes/nall/stream/gzip.hpp index 37bd9778..a6aecfff 100755 --- a/bsnes/nall/stream/gzip.hpp +++ b/bsnes/nall/stream/gzip.hpp @@ -1,9 +1,12 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_GZIP_HPP +#define NALL_STREAM_GZIP_HPP + +#include namespace nall { struct gzipstream : memorystream { - inline gzipstream(const stream &stream) { + gzipstream(const stream &stream) { unsigned size = stream.size(); uint8_t *data = new uint8_t[size]; stream.read(data, size); @@ -18,7 +21,7 @@ struct gzipstream : memorystream { memcpy(pdata, archive.data, psize); } - inline ~gzipstream() { + ~gzipstream() { if(pdata) delete[] pdata; } }; diff --git a/bsnes/nall/stream/http.hpp b/bsnes/nall/stream/http.hpp index b853d51c..63ed6efc 100755 --- a/bsnes/nall/stream/http.hpp +++ b/bsnes/nall/stream/http.hpp @@ -1,24 +1,27 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_HTTP_HPP +#define NALL_STREAM_HTTP_HPP + +#include namespace nall { struct httpstream : stream { - inline bool seekable() const { return true; } - inline bool readable() const { return true; } - inline bool writable() const { return true; } - inline bool randomaccess() const { return true; } + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return true; } + bool randomaccess() const { return true; } - inline unsigned size() const { return psize; } - inline unsigned offset() const { return poffset; } - inline void seek(unsigned offset) const { poffset = offset; } + unsigned size() const { return psize; } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } - inline uint8_t read() const { return pdata[poffset++]; } - inline void write(uint8_t data) const { pdata[poffset++] = data; } + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } - inline uint8_t read(unsigned offset) const { return pdata[offset]; } - inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } - inline httpstream(const string &url, unsigned port) : pdata(nullptr), psize(0), poffset(0) { + httpstream(const string &url, unsigned port) : pdata(nullptr), psize(0), poffset(0) { string uri = url; uri.ltrim<1>("http://"); lstring part = uri.split<1>("/"); @@ -29,7 +32,7 @@ struct httpstream : stream { connection.download(part[1], pdata, psize); } - inline ~httpstream() { + ~httpstream() { if(pdata) delete[] pdata; } diff --git a/bsnes/nall/stream/memory.hpp b/bsnes/nall/stream/memory.hpp index 80bbb240..4fdb5e69 100755 --- a/bsnes/nall/stream/memory.hpp +++ b/bsnes/nall/stream/memory.hpp @@ -1,31 +1,35 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_MEMORY_HPP +#define NALL_STREAM_MEMORY_HPP + +#include namespace nall { struct memorystream : stream { - inline bool seekable() const { return true; } - inline bool readable() const { return true; } - inline bool writable() const { return pwritable; } - inline bool randomaccess() const { return true; } + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return true; } - inline unsigned size() const { return psize; } - inline unsigned offset() const { return poffset; } - inline void seek(unsigned offset) const { poffset = offset; } + uint8_t *data() const { return pdata; } + unsigned size() const { return psize; } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } - inline uint8_t read() const { return pdata[poffset++]; } - inline void write(uint8_t data) const { pdata[poffset++] = data; } + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } - inline uint8_t read(unsigned offset) const { return pdata[offset]; } - inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } - inline memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {} + memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {} - inline memorystream(uint8_t *data, unsigned size) { + memorystream(uint8_t *data, unsigned size) { pdata = data, psize = size, poffset = 0; pwritable = true; } - inline memorystream(const uint8_t *data, unsigned size) { + memorystream(const uint8_t *data, unsigned size) { pdata = (uint8_t*)data, psize = size, poffset = 0; pwritable = false; } diff --git a/bsnes/nall/stream/mmap.hpp b/bsnes/nall/stream/mmap.hpp index a172ccf1..c204f469 100755 --- a/bsnes/nall/stream/mmap.hpp +++ b/bsnes/nall/stream/mmap.hpp @@ -1,24 +1,27 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_MMAP_HPP +#define NALL_STREAM_MMAP_HPP + +#include namespace nall { struct mmapstream : stream { - inline bool seekable() const { return true; } - inline bool readable() const { return true; } - inline bool writable() const { return pwritable; } - inline bool randomaccess() const { return false; } + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return false; } - inline unsigned size() const { return pmmap.size(); } - inline unsigned offset() const { return poffset; } - inline void seek(unsigned offset) const { poffset = offset; } + unsigned size() const { return pmmap.size(); } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } - inline uint8_t read() const { return pdata[poffset++]; } - inline void write(uint8_t data) const { pdata[poffset++] = data; } + uint8_t read() const { return pdata[poffset++]; } + void write(uint8_t data) const { pdata[poffset++] = data; } - inline uint8_t read(unsigned offset) const { return pdata[offset]; } - inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + uint8_t read(unsigned offset) const { return pdata[offset]; } + void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } - inline mmapstream(const string &filename) { + mmapstream(const string &filename) { pmmap.open(filename, filemap::mode::readwrite); pwritable = pmmap.open(); if(!pwritable) pmmap.open(filename, filemap::mode::read); diff --git a/bsnes/nall/stream/stream.hpp b/bsnes/nall/stream/stream.hpp index 3fdee984..d2ef44c5 100755 --- a/bsnes/nall/stream/stream.hpp +++ b/bsnes/nall/stream/stream.hpp @@ -9,6 +9,7 @@ struct stream { virtual bool writable() const = 0; virtual bool randomaccess() const = 0; + virtual uint8_t* data() const { return nullptr; } virtual unsigned size() const = 0; virtual unsigned offset() const = 0; virtual void seek(unsigned offset) const = 0; @@ -16,44 +17,45 @@ struct stream { virtual uint8_t read() const = 0; virtual void write(uint8_t data) const = 0; - inline virtual uint8_t read(unsigned) const { return 0; } - inline virtual void write(unsigned, uint8_t) const {} + virtual uint8_t read(unsigned) const { return 0; } + virtual void write(unsigned, uint8_t) const {} - inline bool end() const { + operator bool() const { + return size(); + } + + bool empty() const { + return size() == 0; + } + + bool end() const { return offset() >= size(); } - inline void copy(uint8_t *&data, unsigned &length) const { - seek(0); - length = size(); - data = new uint8_t[length]; - for(unsigned n = 0; n < length; n++) data[n] = read(); - } - - inline uintmax_t readl(unsigned length = 1) const { + uintmax_t readl(unsigned length = 1) const { uintmax_t data = 0, shift = 0; while(length--) { data |= read() << shift; shift += 8; } return data; } - inline uintmax_t readm(unsigned length = 1) const { + uintmax_t readm(unsigned length = 1) const { uintmax_t data = 0; while(length--) data = (data << 8) | read(); return data; } - inline void read(uint8_t *data, unsigned length) const { + void read(uint8_t *data, unsigned length) const { while(length--) *data++ = read(); } - inline void writel(uintmax_t data, unsigned length = 1) const { + void writel(uintmax_t data, unsigned length = 1) const { while(length--) { write(data); data >>= 8; } } - inline void writem(uintmax_t data, unsigned length = 1) const { + void writem(uintmax_t data, unsigned length = 1) const { uintmax_t shift = 8 * length; while(length--) { shift -= 8; @@ -61,26 +63,26 @@ struct stream { } } - inline void write(const uint8_t *data, unsigned length) const { + void write(const uint8_t *data, unsigned length) const { while(length--) write(*data++); } struct byte { - inline operator uint8_t() const { return s.read(offset); } - inline byte& operator=(uint8_t data) { s.write(offset, data); } - inline byte(const stream &s, unsigned offset) : s(s), offset(offset) {} + operator uint8_t() const { return s.read(offset); } + byte& operator=(uint8_t data) { s.write(offset, data); } + byte(const stream &s, unsigned offset) : s(s), offset(offset) {} private: const stream &s; const unsigned offset; }; - inline byte operator[](unsigned offset) const { + byte operator[](unsigned offset) const { return byte(*this, offset); } - inline stream() {} - inline virtual ~stream() {} + stream() {} + virtual ~stream() {} stream(const stream&) = delete; stream& operator=(const stream&) = delete; }; diff --git a/bsnes/nall/stream/vector.hpp b/bsnes/nall/stream/vector.hpp new file mode 100755 index 00000000..0fa78f7d --- /dev/null +++ b/bsnes/nall/stream/vector.hpp @@ -0,0 +1,36 @@ +#ifndef NALL_STREAM_VECTOR_HPP +#define NALL_STREAM_VECTOR_HPP + +#include +#include + +namespace nall { + +struct vectorstream : stream { + bool seekable() const { return true; } + bool readable() const { return true; } + bool writable() const { return pwritable; } + bool randomaccess() const { return true; } + + uint8_t* data() const { return memory.data(); } + unsigned size() const { return memory.size(); } + unsigned offset() const { return poffset; } + void seek(unsigned offset) const { poffset = offset; } + + uint8_t read() const { return memory[poffset++]; } + void write(uint8_t data) const { memory[poffset++] = data; } + + uint8_t read(unsigned offset) const { return memory[offset]; } + void write(unsigned offset, uint8_t data) const { memory[offset] = data; } + + vectorstream(vector &memory) : memory(memory), poffset(0), pwritable(true) {} + vectorstream(const vector &memory) : memory((vector&)memory), poffset(0), pwritable(false) {} + +protected: + vector &memory; + mutable unsigned poffset, pwritable; +}; + +} + +#endif diff --git a/bsnes/nall/stream/zip.hpp b/bsnes/nall/stream/zip.hpp index dc1d82bc..cad44380 100755 --- a/bsnes/nall/stream/zip.hpp +++ b/bsnes/nall/stream/zip.hpp @@ -1,9 +1,12 @@ -#ifdef NALL_STREAM_INTERNAL_HPP +#ifndef NALL_STREAM_ZIP_HPP +#define NALL_STREAM_ZIP_HPP + +#include namespace nall { struct zipstream : memorystream { - inline zipstream(const stream &stream, const string &filter = "*") { + zipstream(const stream &stream, const string &filter = "*") { unsigned size = stream.size(); uint8_t *data = new uint8_t[size]; stream.read(data, size); @@ -20,7 +23,7 @@ struct zipstream : memorystream { } } - inline ~zipstream() { + ~zipstream() { if(pdata) delete[] pdata; } }; diff --git a/bsnes/nall/string.hpp b/bsnes/nall/string.hpp index 1233dcfb..2fbc1619 100755 --- a/bsnes/nall/string.hpp +++ b/bsnes/nall/string.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/bsnes/nall/vector.hpp b/bsnes/nall/vector.hpp index 19ae4270..c3a768fb 100755 --- a/bsnes/nall/vector.hpp +++ b/bsnes/nall/vector.hpp @@ -21,7 +21,10 @@ namespace nall { unsigned objectsize; public: + operator bool() const { return pool; } T* data() { return pool; } + + bool empty() const { return pool == nullptr; } unsigned size() const { return objectsize; } unsigned capacity() const { return poolsize; } diff --git a/bsnes/nes/interface/interface.cpp b/bsnes/nes/interface/interface.cpp index 668a997d..e4eaa55a 100755 --- a/bsnes/nes/interface/interface.cpp +++ b/bsnes/nes/interface/interface.cpp @@ -4,7 +4,12 @@ namespace Famicom { Interface *interface = nullptr; -void Interface::videoRefresh(const uint16_t *data) { +uint32_t Interface::videoColor(uint9_t source, uint16_t red, uint16_t green, uint16_t blue) { + red >>= 8, green >>= 8, blue >>= 8; + return red << 16 | green << 8 | blue << 0; +} + +void Interface::videoRefresh(const uint32_t *data) { } void Interface::audioSample(const int16_t sample) { @@ -18,4 +23,8 @@ void Interface::message(const string &text) { print(text, "\n"); } +void Interface::loadCartridge(const string &markup, const stream &memory) { + cartridge.load(markup, memory.data(), memory.size()); +} + } diff --git a/bsnes/nes/interface/interface.hpp b/bsnes/nes/interface/interface.hpp index a53af4df..7fd1751c 100755 --- a/bsnes/nes/interface/interface.hpp +++ b/bsnes/nes/interface/interface.hpp @@ -1,9 +1,11 @@ struct Interface { - virtual void videoRefresh(const uint16_t *data); + virtual uint32_t videoColor(uint9_t source, uint16_t red, uint16_t green, uint16_t blue); + virtual void videoRefresh(const uint32_t *data); virtual void audioSample(int16_t sample); virtual int16_t inputPoll(bool port, unsigned device, unsigned id); - virtual void message(const string &text); + + void loadCartridge(const string &markup, const stream &memory); }; extern Interface *interface; diff --git a/bsnes/nes/ppu/ppu.cpp b/bsnes/nes/ppu/ppu.cpp index 115be740..d2f0f5d8 100755 --- a/bsnes/nes/ppu/ppu.cpp +++ b/bsnes/nes/ppu/ppu.cpp @@ -282,7 +282,7 @@ void PPU::scrolly_increment() { // void PPU::raster_pixel() { - uint16 *output = buffer + status.ly * 256; + uint32 *output = buffer + status.ly * 256; unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7)); unsigned palette = 0, object_palette = 0; @@ -325,7 +325,7 @@ void PPU::raster_pixel() { } if(raster_enable() == false) palette = 0; - output[status.lx] = (status.emphasis << 6) | cgram_read(palette); + output[status.lx] = video.palette[(status.emphasis << 6) | cgram_read(palette)]; } void PPU::raster_sprite() { diff --git a/bsnes/nes/ppu/ppu.hpp b/bsnes/nes/ppu/ppu.hpp index c1976356..0a7cca0a 100755 --- a/bsnes/nes/ppu/ppu.hpp +++ b/bsnes/nes/ppu/ppu.hpp @@ -98,7 +98,7 @@ struct PPU : Thread { } oam[8], soam[8]; } raster; - uint16 buffer[256 * 262]; + uint32 buffer[256 * 262]; uint8 ciram[2048]; uint8 cgram[32]; uint8 oam[256]; diff --git a/bsnes/nes/video/video.cpp b/bsnes/nes/video/video.cpp index e725eba1..c3efba53 100755 --- a/bsnes/nes/video/video.cpp +++ b/bsnes/nes/video/video.cpp @@ -5,7 +5,19 @@ namespace Famicom { Video video; -unsigned Video::palette30( +void Video::generate_palette() { + for(unsigned n = 0; n < (1 << 9); n++) palette[n] = generate_color(n, 2.0, 0.0, 1.0, 1.0, 1.8); +} + +Video::Video() { + palette = new unsigned[1 << 9]; +} + +Video::~Video() { + delete[] palette; +} + +uint32_t Video::generate_color( unsigned n, double saturation, double hue, double contrast, double brightness, double gamma ) { @@ -46,43 +58,11 @@ unsigned Video::palette30( q *= saturation; auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); }; - unsigned r = 1023.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q); - unsigned g = 1023.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q); - unsigned b = 1023.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q); - return (uclamp<10>(r) << 20) + (uclamp<10>(g) << 10) + (uclamp<10>(b) << 0); -} + unsigned r = 65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q); + unsigned g = 65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q); + unsigned b = 65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q); -void Video::generate(Format format) { - for(unsigned n = 0; n < (1 << 9); n++) palette[n] = palette30(n, 2.0, 0.0, 1.0, 1.0, 1.8); - - if(format == Format::RGB24) { - for(unsigned n = 0; n < (1 << 9); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); - } - } - - if(format == Format::RGB16) { - for(unsigned n = 0; n < (1 << 9); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); - } - } - - if(format == Format::RGB15) { - for(unsigned n = 0; n < (1 << 9); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); - } - } -} - -Video::Video() { - palette = new unsigned[1 << 9]; -} - -Video::~Video() { - delete[] palette; + return interface->videoColor(n, uclamp<16>(r), uclamp<16>(g), uclamp<16>(b)); } } diff --git a/bsnes/nes/video/video.hpp b/bsnes/nes/video/video.hpp index 6fec2bf9..067c9002 100755 --- a/bsnes/nes/video/video.hpp +++ b/bsnes/nes/video/video.hpp @@ -1,11 +1,12 @@ struct Video { - enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; unsigned *palette; + void generate_palette(); - unsigned palette30(unsigned, double, double, double, double, double); - void generate(Format format); Video(); ~Video(); + +private: + uint32_t generate_color(unsigned, double, double, double, double, double); }; extern Video video; diff --git a/bsnes/ruby/ruby.hpp b/bsnes/ruby/ruby.hpp index e0d5a690..8ea1b21d 100755 --- a/bsnes/ruby/ruby.hpp +++ b/bsnes/ruby/ruby.hpp @@ -7,9 +7,9 @@ #ifndef RUBY_H #define RUBY_H +#include #include #include -#include #include #include #include diff --git a/bsnes/snes/chip/icd2/icd2.cpp b/bsnes/snes/chip/icd2/icd2.cpp index ba70c494..3e3856b9 100755 --- a/bsnes/snes/chip/icd2/icd2.cpp +++ b/bsnes/snes/chip/icd2/icd2.cpp @@ -70,6 +70,7 @@ void ICD2::reset() { pulselock = true; GameBoy::interface = this; + GameBoy::video.generate_palette(); GameBoy::system.init(); GameBoy::system.power(); } diff --git a/bsnes/snes/chip/icd2/interface/interface.cpp b/bsnes/snes/chip/icd2/interface/interface.cpp index bc594bc6..6a4064e4 100755 --- a/bsnes/snes/chip/icd2/interface/interface.cpp +++ b/bsnes/snes/chip/icd2/interface/interface.cpp @@ -7,7 +7,7 @@ void ICD2::lcdScanline() { } unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::ppu.status.ly & 7) * 160); - memcpy(lcd.buffer + offset, GameBoy::ppu.screen + GameBoy::ppu.status.ly * 160, 160 * sizeof(uint16)); + memcpy(lcd.buffer + offset, GameBoy::ppu.screen + GameBoy::ppu.status.ly * 160, 160 * sizeof(uint32)); } void ICD2::joypWrite(bool p15, bool p14) { @@ -80,7 +80,11 @@ void ICD2::joypWrite(bool p15, bool p14) { packetlock = true; } -void ICD2::videoRefresh(const uint16_t *data) { +uint32_t ICD2::videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue) { + return source; +} + +void ICD2::videoRefresh(const uint32_t *data) { } void ICD2::audioSample(int16_t center, int16_t left, int16_t right) { diff --git a/bsnes/snes/chip/icd2/interface/interface.hpp b/bsnes/snes/chip/icd2/interface/interface.hpp index 1c157836..6d4e4c0a 100755 --- a/bsnes/snes/chip/icd2/interface/interface.hpp +++ b/bsnes/snes/chip/icd2/interface/interface.hpp @@ -1,6 +1,7 @@ void lcdScanline(); void joypWrite(bool p15, bool p14); -void videoRefresh(const uint16_t *data); +uint32_t videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue); +void videoRefresh(const uint32_t *data); void audioSample(int16_t center, int16_t left, int16_t right); bool inputPoll(unsigned id); diff --git a/bsnes/snes/chip/icd2/mmio/mmio.cpp b/bsnes/snes/chip/icd2/mmio/mmio.cpp index ce3c15ff..bb227d77 100755 --- a/bsnes/snes/chip/icd2/mmio/mmio.cpp +++ b/bsnes/snes/chip/icd2/mmio/mmio.cpp @@ -1,7 +1,7 @@ #ifdef ICD2_CPP -//convert linear pixel data { 0x00, 0x55, 0xaa, 0xff } to 2bpp planar tiledata -void ICD2::render(const uint16 *source) { +//convert linear pixel data to 2bpp planar tiledata +void ICD2::render(const uint32 *source) { memset(lcd.output, 0x00, 320 * sizeof(uint16)); for(unsigned y = 0; y < 8; y++) { diff --git a/bsnes/snes/chip/icd2/mmio/mmio.hpp b/bsnes/snes/chip/icd2/mmio/mmio.hpp index fdd029de..6172e856 100755 --- a/bsnes/snes/chip/icd2/mmio/mmio.hpp +++ b/bsnes/snes/chip/icd2/mmio/mmio.hpp @@ -1,4 +1,4 @@ -void render(const uint16 *source); +void render(const uint32 *source); uint8 r6000_ly; //SGB BIOS' cache of LY uint8 r6000_row; //SGB BIOS' cache of ROW @@ -13,7 +13,7 @@ unsigned r7800; //VRAM offset uint8 mlt_req; //number of active joypads struct LCD { - uint16 buffer[4 * 160 * 8]; //four tile rows of linear video data + uint32 buffer[4 * 160 * 8]; //four tile rows of linear video data uint16 output[320]; //one tile row of 2bpp video data unsigned row; //active ICD2 rendering tile row } lcd; diff --git a/bsnes/snes/interface/interface.cpp b/bsnes/snes/interface/interface.cpp index ce70e424..e36765e4 100755 --- a/bsnes/snes/interface/interface.cpp +++ b/bsnes/snes/interface/interface.cpp @@ -4,6 +4,11 @@ namespace SuperFamicom { Interface *interface = nullptr; +uint32_t Interface::videoColor(uint19_t source, uint16_t red, uint16_t green, uint16_t blue) { + red >>= 8, green >>= 8, blue >>= 8; + return red << 16 | green << 8 | blue << 0; +} + void Interface::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { } diff --git a/bsnes/snes/interface/interface.hpp b/bsnes/snes/interface/interface.hpp index f1a48c0f..f7f2eca0 100755 --- a/bsnes/snes/interface/interface.hpp +++ b/bsnes/snes/interface/interface.hpp @@ -1,4 +1,5 @@ struct Interface { + virtual uint32_t videoColor(uint19_t source, uint16_t red, uint16_t green, uint16_t blue); virtual void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan); virtual void audioSample(int16_t lsample, int16_t rsample); virtual int16_t inputPoll(bool port, Input::Device device, unsigned index, unsigned id); diff --git a/bsnes/snes/ppu/screen/screen.cpp b/bsnes/snes/ppu/screen/screen.cpp index aaf0427f..f59eea1a 100755 --- a/bsnes/snes/ppu/screen/screen.cpp +++ b/bsnes/snes/ppu/screen/screen.cpp @@ -150,7 +150,7 @@ uint32 PPU::Screen::get_pixel(bool swap) { //======== if(self.regs.display_disable) return 0; - return (self.regs.display_brightness << 15) | output; + return video.palette[self.regs.display_brightness << 15 | output]; } uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) { diff --git a/bsnes/snes/system/video.cpp b/bsnes/snes/system/video.cpp index 2a562f18..43a694e8 100755 --- a/bsnes/snes/system/video.cpp +++ b/bsnes/snes/system/video.cpp @@ -2,48 +2,25 @@ Video video; -unsigned Video::palette30(unsigned color) { - unsigned l = (color >> 15) & 15; - unsigned b = (color >> 10) & 31; - unsigned g = (color >> 5) & 31; - unsigned r = (color >> 0) & 31; +void Video::generate_palette() { + for(unsigned color = 0; color < (1 << 19); color++) { + unsigned l = (color >> 15) & 15; + unsigned b = (color >> 10) & 31; + unsigned g = (color >> 5) & 31; + unsigned r = (color >> 0) & 31; - double L = (1.0 + l) / 16.0; - if(l == 0) L *= 0.5; - unsigned R = L * ((r << 5) + (r << 0)); - unsigned G = L * ((g << 5) + (g << 0)); - unsigned B = L * ((b << 5) + (b << 0)); + double L = (1.0 + l) / 16.0; + if(l == 0) L *= 0.5; + unsigned R = L * (r << 11 | r << 6 | r << 1 | r >> 4); + unsigned G = L * (g << 11 | g << 6 | g << 1 | g >> 4); + unsigned B = L * (b << 11 | b << 6 | b << 1 | b >> 4); - return (R << 20) + (G << 10) + (B << 0); -} - -void Video::generate(Format format) { - for(unsigned n = 0; n < (1 << 19); n++) palette[n] = palette30(n); - - if(format == Format::RGB24) { - for(unsigned n = 0; n < (1 << 19); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); - } - } - - if(format == Format::RGB16) { - for(unsigned n = 0; n < (1 << 19); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); - } - } - - if(format == Format::RGB15) { - for(unsigned n = 0; n < (1 << 19); n++) { - unsigned color = palette[n]; - palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); - } + palette[color] = interface->videoColor(color, R, G, B); } } Video::Video() { - palette = new unsigned[1 << 19]; + palette = new unsigned[1 << 19](); } Video::~Video() { diff --git a/bsnes/snes/system/video.hpp b/bsnes/snes/system/video.hpp index f01cac65..a97e8f46 100755 --- a/bsnes/snes/system/video.hpp +++ b/bsnes/snes/system/video.hpp @@ -1,9 +1,6 @@ struct Video { - enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; unsigned *palette; - - unsigned palette30(unsigned color); - void generate(Format format); + void generate_palette(); Video(); ~Video(); diff --git a/bsnes/target-ui/base.hpp b/bsnes/target-ui/base.hpp index 2ac9432a..7ae6f947 100755 --- a/bsnes/target-ui/base.hpp +++ b/bsnes/target-ui/base.hpp @@ -16,6 +16,8 @@ namespace GBA = GameBoyAdvance; #include #include #include +#include +#include #include #include #include diff --git a/bsnes/target-ui/interface/core.cpp b/bsnes/target-ui/interface/core.cpp index 1826e266..922ead91 100755 --- a/bsnes/target-ui/interface/core.cpp +++ b/bsnes/target-ui/interface/core.cpp @@ -12,18 +12,50 @@ bool InterfaceCore::loadFirmware(string filename, string keyname, uint8_t *targe string firmware = key["firmware"].data; string hash = key["sha256"].data; - uint8_t *data; - unsigned size; - if(file::read({dir(filename),firmware}, data, size) == true) { - if(nall::sha256(data, size) == hash) { - memcpy(targetdata, data, min(targetsize, size)); + if(auto memory = file::read({dir(filename),firmware})) { + if(nall::sha256(memory.data(), memory.size()) == hash) { + memcpy(targetdata, memory.data(), min(targetsize, memory.size())); result = true; } else { MessageWindow::information(Window::None, {"Warning: Firmware SHA256 sum is incorrect:\n\n", dir(filename), firmware}); } - delete[] data; } } return result; } + +/* 5-bit -> 8-bit +static const uint8_t gammaRamp[32] = { + 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, + 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, + 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, + 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, +};*/ + +uint32_t InterfaceCore::color(uint16_t r, uint16_t g, uint16_t b) { + auto gamma = [](uint16_t n) { + double exponent = 1.0 + (double)config->video.gamma * 0.01; + return n < 32768 ? 32767 * pow(((double)n / 32767), exponent) : n; + }; + + auto contrast = [](uint16_t n) { + double contrast = config->video.contrast * 0.01; + signed result = n * contrast; + return max(0, min(65535, result)); + }; + + auto brightness = [](uint16_t n) { + signed brightness = (config->video.brightness - 100) * 256; + signed result = n + brightness; + return max(0, min(65535, result)); + }; + + r = brightness(contrast(gamma(r))); + g = brightness(contrast(gamma(g))); + b = brightness(contrast(gamma(b))); + + if(application->depth == 30) { r >>= 6, g >>= 6, b >>= 6; return r << 20 | g << 10 | b << 0; } + if(application->depth == 24) { r >>= 8, g >>= 8, b >>= 8; return r << 16 | g << 8 | b << 0; } + return 0u; +} diff --git a/bsnes/target-ui/interface/gb/gb.cpp b/bsnes/target-ui/interface/gb/gb.cpp index ede6146d..1c27967d 100755 --- a/bsnes/target-ui/interface/gb/gb.cpp +++ b/bsnes/target-ui/interface/gb/gb.cpp @@ -18,28 +18,26 @@ bool InterfaceGB::cartridgeLoaded() { bool InterfaceGB::loadCartridge(GB::System::Revision revision, const string &filename) { interface->unloadCartridge(); - uint8_t *data; - unsigned size; - + vector memory; if(filename.endswith("/")) { - if(file::read({ filename, "program.rom" }, data, size) == false) return false; - interface->base = { true, filename }; + memory = file::read({filename, "program.rom"}); + interface->base = {true, filename}; } else { - if(file::read(filename, data, size) == false) return false; - interface->base = { false, nall::basename(filename) }; + memory = file::read(filename); + interface->base = {false, nall::basename(filename)}; } + if(memory.empty()) return false; interface->game = interface->base; interface->cartridgeTitle = interface->base.title(); - interface->applyPatch(interface->base, data, size); + interface->applyPatch(interface->base, memory); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = GameBoyCartridge(data, size).markup; + if(markup.empty()) markup = GameBoyCartridge(memory.data(), memory.size()).markup; - GB::cartridge.load(revision, markup, data, size); + GB::cartridge.load(revision, markup, vectorstream{memory}); GB::system.power(); - delete[] data; if(GB::cartridge.ramsize) { filemap fp; @@ -49,7 +47,7 @@ bool InterfaceGB::loadCartridge(GB::System::Revision revision, const string &fil } GB::interface = this; - GB::video.generate(GB::Video::Format::RGB30); + GB::video.generate_palette(); interface->loadCartridge(::Interface::Mode::GB); return true; } @@ -103,19 +101,12 @@ void InterfaceGB::setCheats(const lstring &list) { // -void InterfaceGB::videoRefresh(const uint16_t *data) { - static uint32_t output[160 * 144]; +uint32_t InterfaceGB::videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue) { + return color(red, green, blue); +} - for(unsigned y = 0; y < 144; y++) { - const uint16_t *sp = data + y * 160; - uint32_t *dp = output + y * 160; - for(unsigned x = 0; x < 160; x++) { - uint16_t color = *sp++; - *dp++ = GB::video.palette[color]; - } - } - - interface->videoRefresh(output, 160 * sizeof(uint32_t), 160, 144); +void InterfaceGB::videoRefresh(const uint32_t *data) { + interface->videoRefresh(data, 160 * sizeof(uint32_t), 160, 144); } void InterfaceGB::audioSample(int16_t csample, int16_t lsample, int16_t rsample) { diff --git a/bsnes/target-ui/interface/gb/gb.hpp b/bsnes/target-ui/interface/gb/gb.hpp index 1f2727d1..9445cdf8 100755 --- a/bsnes/target-ui/interface/gb/gb.hpp +++ b/bsnes/target-ui/interface/gb/gb.hpp @@ -16,7 +16,8 @@ struct InterfaceGB : InterfaceCore, GB::Interface { void setCheats(const lstring &list = lstring{}); - void videoRefresh(const uint16_t *data); + uint32_t videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue); + void videoRefresh(const uint32_t *data); void audioSample(int16_t csample, int16_t lsample, int16_t rsample); bool inputPoll(unsigned id); }; diff --git a/bsnes/target-ui/interface/gba/gba.cpp b/bsnes/target-ui/interface/gba/gba.cpp index 94682686..bc3c912a 100755 --- a/bsnes/target-ui/interface/gba/gba.cpp +++ b/bsnes/target-ui/interface/gba/gba.cpp @@ -16,28 +16,26 @@ bool InterfaceGBA::cartridgeLoaded() { bool InterfaceGBA::loadCartridge(const string &filename) { interface->unloadCartridge(); - uint8_t *data; - unsigned size; - + vector memory; if(filename.endswith("/")) { - if(file::read({filename, "program.rom"}, data, size) == false) return false; + memory = file::read({filename, "program.rom"}); interface->base = {true, filename}; } else { - if(file::read(filename, data, size) == false) return false; + memory = file::read(filename); interface->base = {false, nall::basename(filename)}; } + if(memory.empty()) return false; interface->game = interface->base; interface->cartridgeTitle = interface->base.title(); - interface->applyPatch(interface->base, data, size); + interface->applyPatch(interface->base, memory); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = GameBoyAdvanceCartridge(data, size).markup; + if(markup.empty()) markup = GameBoyAdvanceCartridge(memory.data(), memory.size()).markup; - GBA::cartridge.load(markup, data, size); + GBA::cartridge.load(markup, memory.data(), memory.size()); GBA::system.power(); - delete[] data; if(GBA::cartridge.ram_size()) { filemap fp; @@ -46,7 +44,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) { } } - GBA::video.generate(GBA::Video::Format::RGB30); + GBA::video.generate_palette(); interface->loadCartridge(::Interface::Mode::GBA); return true; } @@ -86,19 +84,12 @@ void InterfaceGBA::setCheats(const lstring &list) { // -void InterfaceGBA::videoRefresh(const uint16_t *data) { - static uint32_t output[240 * 160]; +uint32_t InterfaceGBA::videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue) { + return color(red, green, blue); +} - for(unsigned y = 0; y < 160; y++) { - const uint16_t *sp = data + y * 240; - uint32_t *dp = output + y * 240; - for(unsigned x = 0; x < 240; x++) { - uint16_t color = *sp++; - *dp++ = GBA::video.palette[color]; - } - } - - interface->videoRefresh(output, 240 * sizeof(uint32_t), 240, 160); +void InterfaceGBA::videoRefresh(const uint32_t *data) { + interface->videoRefresh(data, 240 * sizeof(uint32_t), 240, 160); } void InterfaceGBA::audioSample(int16_t lsample, int16_t rsample) { diff --git a/bsnes/target-ui/interface/gba/gba.hpp b/bsnes/target-ui/interface/gba/gba.hpp index 2f00f57b..40c7f76c 100755 --- a/bsnes/target-ui/interface/gba/gba.hpp +++ b/bsnes/target-ui/interface/gba/gba.hpp @@ -16,7 +16,8 @@ struct InterfaceGBA : InterfaceCore, GBA::Interface { void setCheats(const lstring &list = lstring{}); - void videoRefresh(const uint16_t *data); + uint32_t videoColor(uint15_t source, uint16_t red, uint16_t green, uint16_t blue); + void videoRefresh(const uint32_t *data); void audioSample(int16_t lsample, int16_t rsample); bool inputPoll(unsigned id); }; diff --git a/bsnes/target-ui/interface/interface.cpp b/bsnes/target-ui/interface/interface.cpp index 02db1917..b28c8a7f 100755 --- a/bsnes/target-ui/interface/interface.cpp +++ b/bsnes/target-ui/interface/interface.cpp @@ -1,6 +1,5 @@ #include "../base.hpp" #include "core.cpp" -#include "palette.cpp" #include "nes/nes.cpp" #include "snes/snes.cpp" #include "gb/gb.cpp" @@ -169,13 +168,12 @@ bool Interface::saveState(unsigned slot) { bool Interface::loadState(unsigned slot) { string filename = game.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" }); - uint8_t *data; - unsigned size; - if(file::read(filename, data, size) == false) { + auto memory = file::read(filename); + if(memory.empty()) { utility->showMessage(string{ "Slot ", slot, " save file not found" }); return false; } - serializer s(data, size); + serializer s(memory.data(), memory.size()); bool result = unserialize(s); utility->showMessage(result == true ? string{ "Loaded state ", slot } : "Failed to load state"); return result; @@ -185,6 +183,15 @@ void Interface::setCheatCodes(const lstring &list) { if(core) return core->setCheats(list); } +void Interface::updatePalette() { + switch(mode()) { + case Mode::NES: return NES::video.generate_palette(); + case Mode::SNES: return SNES::video.generate_palette(); + case Mode::GB: return GB::video.generate_palette(); + case Mode::GBA: return GBA::video.generate_palette(); + } +} + string Interface::sha256() { switch(mode()) { case Mode::NES: return NES::cartridge.sha256(); @@ -205,13 +212,13 @@ Interface::Interface() : core(nullptr) { //internal -bool Interface::applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size) { +bool Interface::applyPatch(CartridgePath &filepath, vector &memory) { string patchname = filepath.filename("patch.bps", ".bps"); if(file::exists(patchname) == false) return false; bpspatch bps; bps.modify(patchname); - bps.source(data, size); + bps.source(memory.data(), memory.size()); unsigned targetSize = bps.size(); uint8_t *targetData = new uint8_t[targetSize]; bps.target(targetData, targetSize); @@ -220,9 +227,9 @@ bool Interface::applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &si return false; } - delete[] data; - data = targetData; - size = targetSize; + memory.resize(targetSize); + memcpy(memory.data(), targetData, targetSize); + delete[] targetData; return true; } @@ -230,7 +237,7 @@ void Interface::videoRefresh(const uint32_t *input, unsigned inputPitch, unsigne uint32_t *output; unsigned outputPitch; - if(filter.opened()) { + if(application->depth == 30 && filter.opened()) { filter.render(input, inputPitch, width, height); input = filter.data; inputPitch = filter.pitch; @@ -242,11 +249,21 @@ void Interface::videoRefresh(const uint32_t *input, unsigned inputPitch, unsigne inputPitch >>= 2, outputPitch >>= 2; for(unsigned y = 0; y < height; y++) { - const uint32_t *sp = input + y * inputPitch; - uint32_t *dp = output + y * outputPitch; - for(unsigned x = 0; x < width; x++) { - uint32_t color = *sp++; - *dp++ = palette((color >> 20) & 1023, (color >> 10) & 1023, (color >> 0) & 1023); + memcpy(output + y * outputPitch, input + y * inputPitch, width * sizeof(uint32_t)); + } + + if(config->video.maskOverscan && (mode() == Mode::NES || mode() == Mode::SNES)) { + unsigned h = config->video.maskOverscanHorizontal; + unsigned v = config->video.maskOverscanVertical; + + if(h) for(unsigned y = 0; y < height; y++) { + memset(output + y * outputPitch, 0, h * sizeof(uint32_t)); + memset(output + y * outputPitch + (width - h), 0, h * sizeof(uint32_t)); + } + + if(v) for(unsigned y = 0; y < v; y++) { + memset(output + y * outputPitch, 0, width * sizeof(uint32_t)); + memset(output + (height - 1 - y) * outputPitch, 0, width * sizeof(uint32_t)); } } diff --git a/bsnes/target-ui/interface/interface.hpp b/bsnes/target-ui/interface/interface.hpp index 1e0153c2..e4584669 100755 --- a/bsnes/target-ui/interface/interface.hpp +++ b/bsnes/target-ui/interface/interface.hpp @@ -1,7 +1,6 @@ -#include "palette.hpp" - struct InterfaceCore { bool loadFirmware(string filename, string keyname, uint8_t *targetdata, unsigned targetsize); + uint32_t color(uint16_t red, uint16_t green, uint16_t blue); virtual string markup() = 0; virtual bool cartridgeLoaded() = 0; @@ -69,11 +68,12 @@ struct Interface : property { bool saveState(unsigned slot); bool loadState(unsigned slot); void setCheatCodes(const lstring &list = lstring{}); + void updatePalette(); string sha256(); Interface(); - bool applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size); + bool applyPatch(CartridgePath &filepath, vector &memory); void videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height); CartridgePath base; //base cartridge connected to emulated system diff --git a/bsnes/target-ui/interface/nes/nes.cpp b/bsnes/target-ui/interface/nes/nes.cpp index bc4b040e..7c4f0831 100755 --- a/bsnes/target-ui/interface/nes/nes.cpp +++ b/bsnes/target-ui/interface/nes/nes.cpp @@ -29,28 +29,26 @@ bool InterfaceNES::cartridgeLoaded() { bool InterfaceNES::loadCartridge(const string &filename) { interface->unloadCartridge(); - uint8_t *data; - unsigned size; - + vector memory; if(filename.endswith("/")) { - if(file::read({filename, "program.rom"}, data, size) == false) return false; + memory = file::read({filename, "program.rom"}); interface->base = {true, filename}; } else { - file::read(filename, data, size); + memory = file::read(filename); interface->base = {false, nall::basename(filename)}; } + if(memory.empty()) return false; interface->game = interface->base; interface->cartridgeTitle = interface->base.title(); - interface->applyPatch(interface->base, data, size); + interface->applyPatch(interface->base, memory); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = FamicomCartridge(data, size).markup; + if(markup.empty()) markup = FamicomCartridge(memory.data(), memory.size()).markup; - NES::cartridge.load(markup, data, size); + NES::cartridge.load(markup, memory.data(), memory.size()); NES::system.power(); - delete[] data; if(NES::cartridge.ram_size()) { filemap fp; @@ -60,7 +58,7 @@ bool InterfaceNES::loadCartridge(const string &filename) { } interface->loadCartridge(::Interface::Mode::NES); - NES::video.generate(NES::Video::Format::RGB30); + NES::video.generate_palette(); return true; } @@ -116,34 +114,12 @@ void InterfaceNES::setCheats(const lstring &list) { // -void InterfaceNES::videoRefresh(const uint16_t *data) { - static uint32_t output[256 * 240]; +uint32_t InterfaceNES::videoColor(uint9_t source, uint16_t red, uint16_t green, uint16_t blue) { + return color(red, green, blue); +} - for(unsigned y = 0; y < 240; y++) { - const uint16_t *sp = data + y * 256; - uint32_t *dp = output + y * 256; - for(unsigned x = 0; x < 256; x++) { - uint32_t color = *sp++; - *dp++ = NES::video.palette[color]; - } - } - - if(config->video.maskOverscan) { - unsigned osw = config->video.maskOverscanHorizontal; - unsigned osh = config->video.maskOverscanVertical; - - for(unsigned y = 0; y < 240; y++) { - uint32_t *dp = output + y * 256; - if(y < osh || y >= 240 - osh) { - memset(dp, 0, 256 * sizeof(uint32_t)); - } else { - memset(dp + 0, 0, osw * sizeof(uint32_t)); - memset(dp + 256 - osw, 0, osw * sizeof(uint32_t)); - } - } - } - - interface->videoRefresh(output, 256 * sizeof(uint32_t), 256, 240); +void InterfaceNES::videoRefresh(const uint32_t *data) { + interface->videoRefresh(data, 256 * sizeof(uint32_t), 256, 240); } void InterfaceNES::audioSample(int16_t sample) { diff --git a/bsnes/target-ui/interface/nes/nes.hpp b/bsnes/target-ui/interface/nes/nes.hpp index f502de49..c3b3343d 100755 --- a/bsnes/target-ui/interface/nes/nes.hpp +++ b/bsnes/target-ui/interface/nes/nes.hpp @@ -18,7 +18,8 @@ struct InterfaceNES : InterfaceCore, NES::Interface { void setCheats(const lstring &list = lstring{}); - void videoRefresh(const uint16_t *data); + uint32_t videoColor(uint9_t source, uint16_t red, uint16_t green, uint16_t blue); + void videoRefresh(const uint32_t *data); void audioSample(int16_t sample); int16_t inputPoll(bool port, unsigned device, unsigned id); }; diff --git a/bsnes/target-ui/interface/palette.cpp b/bsnes/target-ui/interface/palette.cpp deleted file mode 100755 index f8a52209..00000000 --- a/bsnes/target-ui/interface/palette.cpp +++ /dev/null @@ -1,50 +0,0 @@ -Palette palette; - -unsigned Palette::operator()(unsigned r, unsigned g, unsigned b) const { - return red[r] + green[g] + blue[b]; -} - -/* 5-bit -> 8-bit -const uint8_t Palette::gammaRamp[32] = { - 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, - 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, - 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, - 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, -}; -*/ - -void Palette::update() { - double exponent = 1.0 + (double)config->video.gamma * 0.01; - for(unsigned n = 0; n < 1024; n++) { - unsigned result = (n < 512 ? 511 * pow(((double)n / 511), exponent) : n); - color[n] = result; - } - - double contrast = config->video.contrast * 0.01; - for(unsigned n = 0; n < 1024; n++) { - signed result = color[n] * contrast; - color[n] = max(0, min(1023, result)); - } - - signed brightness = (config->video.brightness - 100) * 4; - for(unsigned n = 0; n < 1024; n++) { - signed result = color[n] + brightness; - color[n] = max(0, min(1023, result)); - } - - if(application->depth == 30) { - for(unsigned n = 0; n < 1024; n++) { - red[n] = color[n] << 20; - green[n] = color[n] << 10; - blue[n] = color[n] << 0; - } - } - - if(application->depth == 24) { - for(unsigned n = 0; n < 1024; n++) { - red[n] = (color[n] >> 2) << 16; - green[n] = (color[n] >> 2) << 8; - blue[n] = (color[n] >> 2) << 0; - } - } -} diff --git a/bsnes/target-ui/interface/palette.hpp b/bsnes/target-ui/interface/palette.hpp deleted file mode 100755 index c9072623..00000000 --- a/bsnes/target-ui/interface/palette.hpp +++ /dev/null @@ -1,10 +0,0 @@ -struct Palette { - alwaysinline unsigned operator()(unsigned r, unsigned g, unsigned b) const; - void update(); - -private: - uint32_t color[1024]; - uint32_t red[1024], green[1024], blue[1024]; -}; - -extern Palette palette; diff --git a/bsnes/target-ui/interface/snes/snes.cpp b/bsnes/target-ui/interface/snes/snes.cpp index ebff8243..fea9249c 100755 --- a/bsnes/target-ui/interface/snes/snes.cpp +++ b/bsnes/target-ui/interface/snes/snes.cpp @@ -37,178 +37,156 @@ bool InterfaceSNES::cartridgeLoaded() { return SNES::cartridge.loaded(); } -bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartridge, uint8_t *&data, unsigned &size) { - data = nullptr, size = 0u; +vector InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartridge) { + vector memory; auto backup = cartridge; string suffix; if(filename.endswith("/")) { - cartridge = { true, filename }; + cartridge = {true, filename}; } else { - suffix = { ".", extension(filename) }; - cartridge = { false, nall::basename(filename) }; + suffix = {".", extension(filename)}; + cartridge = {false, nall::basename(filename)}; } - if(file::read(cartridge.filename("program.rom", suffix), data, size) == false) { - cartridge = backup; - return false; - } - interface->applyPatch(cartridge, data, size); - return true; + memory = file::read(cartridge.filename("program.rom", suffix)); + interface->applyPatch(cartridge, memory); + if(memory.empty()) cartridge = backup; + return memory; } bool InterfaceSNES::loadCartridge(string basename) { interface->unloadCartridge(); - uint8_t *data; - unsigned size; - if(loadCartridge(basename, interface->base, data, size) == false) return false; + auto memory = loadCartridge(basename, interface->base); + if(memory.empty()) return false; interface->game = interface->base; interface->cartridgeTitle = interface->base.title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SuperFamicomCartridge(data, size).markup; + if(markup.empty()) markup = SuperFamicomCartridge(memory.data(), memory.size()).markup; - SNES::cartridge.rom.copy(data, size); + SNES::cartridge.rom.copy(memory.data(), memory.size()); SNES::cartridge.load(SNES::Cartridge::Mode::Normal, markup); SNES::system.power(); - delete[] data; - loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB30); + SNES::video.generate_palette(); return true; } bool InterfaceSNES::loadSatellaviewSlottedCartridge(string basename, string slotname) { interface->unloadCartridge(); - uint8_t *data[2]; - unsigned size[2]; - if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot[0], data[1], size[1]); + auto memory = loadCartridge(basename, interface->base); + if(memory.empty()) return false; + auto memoryBS = loadCartridge(slotname, interface->slot[0]); - interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files + interface->game = memoryBS.empty() ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files interface->cartridgeTitle = interface->base.title(); - if(data[1]) interface->cartridgeTitle.append(" + ", interface->slot[0].title()); + if(memoryBS) interface->cartridgeTitle.append(" + ", interface->slot[0].title()); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(memory.data(), memory.size()).markup; - SNES::cartridge.rom.copy(data[0], size[0]); - if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.rom.copy(memory.data(), memory.size()); + if(memoryBS) SNES::bsxflash.memory.copy(memoryBS.data(), memoryBS.size()); SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, markup); SNES::system.power(); - delete[] data[0]; - if(data[1]) delete[] data[1]; - loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB30); + SNES::video.generate_palette(); return true; } bool InterfaceSNES::loadSatellaviewCartridge(string basename, string slotname) { interface->unloadCartridge(); - uint8_t *data[2]; - unsigned size[2]; - if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot[0], data[1], size[1]); + auto memory = loadCartridge(basename, interface->base); + if(memory.empty()) return false; + auto memoryBS = loadCartridge(slotname, interface->slot[0]); - interface->game = !data[1] ? interface->base : interface->slot[0]; + interface->game = memoryBS.empty() ? interface->base : interface->slot[0]; interface->cartridgeTitle = interface->base.title(); - if(data[1]) interface->cartridgeTitle = interface->slot[0].title(); + if(memoryBS) interface->cartridgeTitle = interface->slot[0].title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(memory.data(), memory.size()).markup; - SNES::cartridge.rom.copy(data[0], size[0]); - if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.rom.copy(memory.data(), memory.size()); + if(memoryBS) SNES::bsxflash.memory.copy(memoryBS.data(), memoryBS.size()); SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, markup); SNES::system.power(); - delete[] data[0]; - if(data[1]) delete[] data[1]; - loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB30); + SNES::video.generate_palette(); return true; } bool InterfaceSNES::loadSufamiTurboCartridge(string basename, string slotAname, string slotBname) { interface->unloadCartridge(); - uint8_t *data[3]; - unsigned size[3]; - if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotAname, interface->slot[0], data[1], size[1]); - loadCartridge(slotBname, interface->slot[1], data[2], size[2]); + auto memory = loadCartridge(basename, interface->base); + if(memory.empty()) return false; + auto memorySTA = loadCartridge(slotAname, interface->slot[0]); + auto memorySTB = loadCartridge(slotBname, interface->slot[1]); - interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files + interface->game = memorySTA.empty() ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files interface->cartridgeTitle = interface->base.title(); - if( data[1] && !data[2]) interface->cartridgeTitle = interface->slot[0].title(); - if(!data[1] && data[2]) interface->cartridgeTitle = interface->slot[1].title(); - if( data[1] && data[2]) interface->cartridgeTitle = { + if( memorySTA && !memorySTB) interface->cartridgeTitle = interface->slot[0].title(); + if(!memorySTA && memorySTB) interface->cartridgeTitle = interface->slot[1].title(); + if( memorySTA && memorySTB) interface->cartridgeTitle = { interface->slot[0].title(), " + ", interface->slot[1].title() }; string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(memory.data(), memory.size()).markup; - SNES::cartridge.rom.copy(data[0], size[0]); - if(data[1]) SNES::sufamiturbo.slotA.rom.copy(data[1], size[1]); - if(data[2]) SNES::sufamiturbo.slotB.rom.copy(data[1], size[1]); + SNES::cartridge.rom.copy(memory.data(), memory.size()); + if(memorySTA) SNES::sufamiturbo.slotA.rom.copy(memory.data(), memory.size()); + if(memorySTB) SNES::sufamiturbo.slotB.rom.copy(memory.data(), memory.size()); SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, markup); SNES::system.power(); - delete[] data[0]; - if(data[1]) delete[] data[1]; - if(data[2]) delete[] data[2]; - loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB30); + SNES::video.generate_palette(); return true; } bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname) { interface->unloadCartridge(); - uint8_t *data[2]; - unsigned size[2]; - if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot[0], data[1], size[1]); + auto memory = loadCartridge(basename, interface->base); + if(memory.empty()) return false; + auto memoryGB = loadCartridge(slotname, interface->slot[0]); - interface->game = !data[1] ? interface->base : interface->slot[0]; + interface->game = memoryGB.empty() ? interface->base : interface->slot[0]; interface->cartridgeTitle = interface->base.title(); - if(data[1]) interface->cartridgeTitle = interface->slot[0].title(); + if(memoryGB) interface->cartridgeTitle = interface->slot[0].title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(memory.data(), memory.size()).markup; string gbMarkup; gbMarkup.readfile(interface->slot[0].filename("manifest.xml", ".xml")); - if(gbMarkup.empty()) gbMarkup = GameBoyCartridge(data[1], size[1]).markup; + if(gbMarkup.empty()) gbMarkup = GameBoyCartridge(memoryGB.data(), memoryGB.size()).markup; - SNES::cartridge.rom.copy(data[0], size[0]); - GB::cartridge.load(GB::System::Revision::SuperGameBoy, gbMarkup, data[1], size[1]); + SNES::cartridge.rom.copy(memory.data(), memory.size()); + GB::cartridge.load(GB::System::Revision::SuperGameBoy, gbMarkup, vectorstream{memoryGB}); SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, markup); SNES::system.power(); - delete[] data[0]; - if(data[1]) delete[] data[1]; - loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB30); + SNES::video.generate_palette(); return true; } @@ -253,21 +231,15 @@ void InterfaceSNES::loadMemory() { string filename = memoryName(memory); if(filename.empty()) continue; - uint8_t *data; - unsigned size; - if(file::read(filename, data, size)) { - memcpy(memory.data, data, min(memory.size, size)); - delete[] data; + if(auto read = file::read(filename)) { + memcpy(memory.data, read.data(), min(memory.size, read.size())); } } if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { if(GB::cartridge.ramsize) { - uint8_t *data; - unsigned size; - if(file::read(interface->slot[0].filename("save.ram", ".sav"), data, size)) { - memcpy(GB::cartridge.ramdata, data, min(GB::cartridge.ramsize, size)); - delete[] data; + if(auto read = file::read(interface->slot[0].filename("save.ram", ".sav"))) { + memcpy(GB::cartridge.ramdata, read.data(), min(GB::cartridge.ramsize, read.size())); } } } @@ -334,41 +306,20 @@ void InterfaceSNES::setCheats(const lstring &list) { // -void InterfaceSNES::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { - static uint32_t output[512 * 480]; +uint32_t InterfaceSNES::videoColor(uint19_t source, uint16_t red, uint16_t green, uint16_t blue) { + return color(red, green, blue); +} - unsigned width = 256 << hires; - unsigned height = 240 << interlace; - unsigned pitch = 1024 >> interlace; +void InterfaceSNES::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { + unsigned width = 256 << hires; + unsigned height = 240 << interlace; + unsigned pitch = 1024 >> interlace; //skip first line; as it is always blank (by SNES design) - if(overscan == false) data += 1 * 1024; // 8 + 224 + 8 - if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0 + if(overscan == false) data += 1 * 1024; // 8 + 224 + 8 + if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0 - for(unsigned y = 0; y < height; y++) { - const uint32_t *sp = data + y * pitch; - uint32_t *dp = output + y * 512; - for(unsigned x = 0; x < width; x++) { - *dp++ = SNES::video.palette[*sp++]; - } - } - - if(config->video.maskOverscan) { - unsigned osw = config->video.maskOverscanHorizontal << hires; - unsigned osh = config->video.maskOverscanVertical << interlace; - - for(unsigned y = 0; y < height; y++) { - uint32_t *dp = output + y * 512; - if(y < osh || y >= height - osh) { - memset(dp, 0, width * sizeof(uint32_t)); - } else { - memset(dp + 0, 0, osw * sizeof(uint32_t)); - memset(dp + width - osw, 0, osw * sizeof(uint32_t)); - } - } - } - - interface->videoRefresh(output, 512 * sizeof(uint32_t), width, height); + interface->videoRefresh(data, pitch * sizeof(uint32_t), width, height); } void InterfaceSNES::audioSample(int16_t lsample, int16_t rsample) { diff --git a/bsnes/target-ui/interface/snes/snes.hpp b/bsnes/target-ui/interface/snes/snes.hpp index 047350a1..642c31fe 100755 --- a/bsnes/target-ui/interface/snes/snes.hpp +++ b/bsnes/target-ui/interface/snes/snes.hpp @@ -6,7 +6,7 @@ struct InterfaceSNES : InterfaceCore, SNES::Interface { void setController(bool port, unsigned device); bool cartridgeLoaded(); - bool loadCartridge(const string &filename, CartridgePath &cartridge, uint8_t *&data, unsigned &size); + vector loadCartridge(const string &filename, CartridgePath &cartridge); bool loadCartridge(string basename); bool loadSatellaviewSlottedCartridge(string basename, string slotname); bool loadSatellaviewCartridge(string basename, string slotname); @@ -27,6 +27,7 @@ struct InterfaceSNES : InterfaceCore, SNES::Interface { void setCheats(const lstring &list = lstring{}); + uint32_t videoColor(uint19_t source, uint16_t red, uint16_t green, uint16_t blue); void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan); void audioSample(int16_t lsample, int16_t rsample); int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id); diff --git a/bsnes/target-ui/main.cpp b/bsnes/target-ui/main.cpp index 65c74c31..675da4e6 100755 --- a/bsnes/target-ui/main.cpp +++ b/bsnes/target-ui/main.cpp @@ -88,7 +88,6 @@ Application::Application(int argc, char **argv) { video.driver("None"); video.init(); } - palette.update(); utility->bindVideoFilter(); utility->bindVideoShader(); diff --git a/bsnes/target-ui/settings/video.cpp b/bsnes/target-ui/settings/video.cpp index 0f292f9f..420f2009 100755 --- a/bsnes/target-ui/settings/video.cpp +++ b/bsnes/target-ui/settings/video.cpp @@ -103,5 +103,5 @@ void VideoSettings::synchronize() { overscanHorizontal.value.setText({ config->video.maskOverscanHorizontal, "px" }); overscanVertical.value.setText({ config->video.maskOverscanVertical, "px" }); - palette.update(); + interface->updatePalette(); }