From 616372e96b705a9ee005e661e9b4caecc1f0ad51 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 27 Apr 2012 22:12:53 +1000 Subject: [PATCH] Update to v088r03 release. byuu says: static vector file::read(const string &filename); replaces: static bool file::read(const string &filename, uint8_t *&data, unsigned &size); This allows automatic deletion of the underlying data. Added vectorstream, which is obviously a vector wrapper for a data stream. Plan is for all data accesses inside my emulation cores to take stream objects, especially MSU1. This lets you feed the core anything: memorystream, filestream, zipstream, gzipstream, httpstream, etc. There will still be exceptions for link and serial, those need actual library files on disk. But those aren't official hardware devices anyway. So to help with speed a bit, I'm rethinking the video rendering path. Previous system: - core outputs system-native samples (SNES = 19-bit LRGB, NES = 9-bit emphasis+palette, DMG = 2-bit grayscale, etc.) - interfaceSystem transforms samples to 30-bit via lookup table inside the emulation core - interfaceSystem masks off overscan areas, if enabled - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI transforms 30-bit video to native display depth (24-bit or 30-bit), and applies color-adjustments (gamma, etc) at the same time New system: - all cores now generate an internal palette, and call Interface::videoColor(uint32_t source, uint16_t red, uint16_t green, uint16_t blue) to get native display color post-adjusted (gamma, etc applied already.) - all cores output to uint32_t* buffer now (output video.palette[color] instead of just color) - interfaceUI runs filter to produce new target buffer, if enabled - interfaceUI memcpy()'s buffer to the video card videoColor() is pretty neat. source is the raw pixel (as per the old-format, 19-bit SNES, 9-bit NES, etc), and you can create a color from that if you really want to. Or return that value to get a buffer just like v088 and below. red, green, blue are 16-bits per channel, because why the hell not, right? Just lop off all the bits you don't want. If you have more bits on your display than that, fuck you :P The last step is extremely difficult to avoid. Video cards can and do have pitches that differ from the width of the texture. Trying to make the core account for this would be really awful. And even if we did that, the emulation routine would need to write directly to a video card RAM buffer. Some APIs require you to lock the video buffer while writing, so this would leave the video buffer locked for a long time. Probably not catastrophic, but still awful. And lastly, if the emulation core tried writing directly to the display texture, software filters would no longer be possible (unless you -really- jump through hooks and divert to a memory buffer when a filter is enabled, but ... fuck.) Anyway, the point of all that work was to eliminate an extra video copy, and the need for a really painful 30-bit to 24-bit conversion (three shifts, three masks, three array indexes.) So this basically reverts us, performance-wise, to where we were pre-30 bit support. [...] The downside to this is that we're going to need a filter for each output depth. Since the array type is uint32_t*, and I don't intend to support higher or lower depths, we really only need 24+30-bit versions of each filter. Kinda shitty, but oh well. --- bsnes/base/base.hpp | 7 +- bsnes/gb/cartridge/cartridge.cpp | 24 +-- bsnes/gb/cartridge/cartridge.hpp | 2 +- bsnes/gb/interface/interface.cpp | 7 +- bsnes/gb/interface/interface.hpp | 3 +- bsnes/gb/ppu/cgb.cpp | 4 +- bsnes/gb/ppu/dmg.cpp | 4 +- bsnes/gb/ppu/ppu.hpp | 2 +- bsnes/gb/video/video.cpp | 71 +++---- bsnes/gb/video/video.hpp | 12 +- bsnes/gba/interface/interface.cpp | 7 +- bsnes/gba/interface/interface.hpp | 3 +- bsnes/gba/ppu/ppu.cpp | 2 +- bsnes/gba/ppu/ppu.hpp | 2 +- bsnes/gba/ppu/screen.cpp | 8 +- bsnes/gba/video/video.cpp | 41 +--- bsnes/gba/video/video.hpp | 4 +- bsnes/nall/array.hpp | 159 ---------------- bsnes/nall/bit.hpp | 2 + bsnes/nall/bitarray.hpp | 79 -------- bsnes/nall/file.hpp | 23 +-- bsnes/nall/gzip.hpp | 10 +- bsnes/nall/ips.hpp | 10 - bsnes/nall/png.hpp | 10 +- bsnes/nall/stream/auto.hpp | 3 +- bsnes/nall/stream/file.hpp | 25 +-- bsnes/nall/stream/gzip.hpp | 9 +- bsnes/nall/stream/http.hpp | 31 +-- bsnes/nall/stream/memory.hpp | 34 ++-- bsnes/nall/stream/mmap.hpp | 29 +-- bsnes/nall/stream/stream.hpp | 46 ++--- bsnes/nall/stream/vector.hpp | 36 ++++ bsnes/nall/stream/zip.hpp | 9 +- bsnes/nall/string.hpp | 1 - bsnes/nall/vector.hpp | 3 + bsnes/nes/interface/interface.cpp | 11 +- bsnes/nes/interface/interface.hpp | 6 +- bsnes/nes/ppu/ppu.cpp | 4 +- bsnes/nes/ppu/ppu.hpp | 2 +- bsnes/nes/video/video.cpp | 54 ++---- bsnes/nes/video/video.hpp | 7 +- bsnes/ruby/ruby.hpp | 2 +- bsnes/snes/chip/icd2/icd2.cpp | 1 + bsnes/snes/chip/icd2/interface/interface.cpp | 8 +- bsnes/snes/chip/icd2/interface/interface.hpp | 3 +- bsnes/snes/chip/icd2/mmio/mmio.cpp | 4 +- bsnes/snes/chip/icd2/mmio/mmio.hpp | 4 +- bsnes/snes/interface/interface.cpp | 5 + bsnes/snes/interface/interface.hpp | 1 + bsnes/snes/ppu/screen/screen.cpp | 2 +- bsnes/snes/system/video.cpp | 49 ++--- bsnes/snes/system/video.hpp | 5 +- bsnes/target-ui/base.hpp | 2 + bsnes/target-ui/interface/core.cpp | 44 ++++- bsnes/target-ui/interface/gb/gb.cpp | 39 ++-- bsnes/target-ui/interface/gb/gb.hpp | 3 +- bsnes/target-ui/interface/gba/gba.cpp | 35 ++-- bsnes/target-ui/interface/gba/gba.hpp | 3 +- bsnes/target-ui/interface/interface.cpp | 49 +++-- bsnes/target-ui/interface/interface.hpp | 6 +- bsnes/target-ui/interface/nes/nes.cpp | 50 ++--- bsnes/target-ui/interface/nes/nes.hpp | 3 +- bsnes/target-ui/interface/palette.cpp | 50 ----- bsnes/target-ui/interface/palette.hpp | 10 - bsnes/target-ui/interface/snes/snes.cpp | 187 +++++++------------ bsnes/target-ui/interface/snes/snes.hpp | 3 +- bsnes/target-ui/main.cpp | 1 - bsnes/target-ui/settings/video.cpp | 2 +- 68 files changed, 516 insertions(+), 861 deletions(-) delete mode 100755 bsnes/nall/array.hpp delete mode 100755 bsnes/nall/bitarray.hpp create mode 100755 bsnes/nall/stream/vector.hpp delete mode 100755 bsnes/target-ui/interface/palette.cpp delete mode 100755 bsnes/target-ui/interface/palette.hpp 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(); }