mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-07-31 09:10:23 +02:00
Update to v102r18 release.
byuu says: This WIP fixes all the critical pending issues I had open. I'm sure there's many more that simply didn't make their way into said list. So by all means, please report important issues you're aware of so they can get fixed. Changelog: - ruby: add variable texture support to GDI video driver [bug reported by Cydrak] - ruby: minor cleanups to XShm video driver - ruby: fix handling of up+down, left+right hat cases for XInput driver [bug reported by Cydrak] - nall: fixed vector class so that compilation with GCC 7.1 should succeed [SuperMikeMan] - sfc: initialize most DSP registers to random values to fix Magical Drop [Jonas Quinn] - sfc: lower PPU brightness when luma=0 from 50% scale to 25% scale; helps scenes like Final Fantasy III's intro
This commit is contained in:
@@ -12,7 +12,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "102.17";
|
static const string Version = "102.18";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@@ -246,6 +246,15 @@ auto DSP::power() -> void {
|
|||||||
voice[n].vidx = n * 0x10;
|
voice[n].vidx = n * 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto r : range(0x80)) {
|
||||||
|
REG(r) = random(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto v : range(8)) {
|
||||||
|
REG(v * 0x10 + ENVX) = 0;
|
||||||
|
REG(v * 0x10 + OUTX) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
REG(FLG) = 0xe0;
|
REG(FLG) = 0xe0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -139,7 +139,9 @@ auto Interface::videoColor(uint32 color) -> uint64 {
|
|||||||
uint b = color.bits(10,14);
|
uint b = color.bits(10,14);
|
||||||
uint l = color.bits(15,18);
|
uint l = color.bits(15,18);
|
||||||
|
|
||||||
double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.5);
|
//luma=0 is not 100% black; but it's much darker than normal linear scaling
|
||||||
|
//exact effect seems to be analog; requires > 24-bit color depth to represent accurately
|
||||||
|
double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.25);
|
||||||
uint64 R = L * image::normalize(r, 5, 16);
|
uint64 R = L * image::normalize(r, 5, 16);
|
||||||
uint64 G = L * image::normalize(g, 5, 16);
|
uint64 G = L * image::normalize(g, 5, 16);
|
||||||
uint64 B = L * image::normalize(b, 5, 16);
|
uint64 B = L * image::normalize(b, 5, 16);
|
||||||
|
@@ -81,11 +81,11 @@ struct vector {
|
|||||||
auto take(uint offset) -> T;
|
auto take(uint offset) -> T;
|
||||||
|
|
||||||
//iterator.hpp
|
//iterator.hpp
|
||||||
auto begin() { return vector_iterator<T>{*this, 0}; }
|
auto begin() -> vector_iterator<T> { return vector_iterator<T>{*this, 0}; }
|
||||||
auto end() { return vector_iterator<T>{*this, size()}; }
|
auto end() -> vector_iterator<T> { return vector_iterator<T>{*this, size()}; }
|
||||||
|
|
||||||
auto begin() const { return vector_iterator_const<T>{*this, 0}; }
|
auto begin() const -> vector_iterator_const<T> { return vector_iterator_const<T>{*this, 0}; }
|
||||||
auto end() const { return vector_iterator_const<T>{*this, size()}; }
|
auto end() const -> vector_iterator_const<T> { return vector_iterator_const<T>{*this, size()}; }
|
||||||
|
|
||||||
//utility.hpp
|
//utility.hpp
|
||||||
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void;
|
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void;
|
||||||
|
@@ -55,10 +55,10 @@ struct InputJoypadXInput {
|
|||||||
|
|
||||||
int16_t hatX = 0;
|
int16_t hatX = 0;
|
||||||
int16_t hatY = 0;
|
int16_t hatY = 0;
|
||||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hatY = -32768;
|
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hatY -= 32767;
|
||||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hatY = +32767;
|
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hatY += 32767;
|
||||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hatX = -32768;
|
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hatX -= 32767;
|
||||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hatX = +32767;
|
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hatX += 32767;
|
||||||
|
|
||||||
assign(jp.hid, HID::Joypad::GroupID::Hat, 0, hatX);
|
assign(jp.hid, HID::Joypad::GroupID::Hat, 0, hatX);
|
||||||
assign(jp.hid, HID::Joypad::GroupID::Hat, 1, hatY);
|
assign(jp.hid, HID::Joypad::GroupID::Hat, 1, hatY);
|
||||||
|
@@ -3,16 +3,18 @@
|
|||||||
struct VideoGDI : Video {
|
struct VideoGDI : Video {
|
||||||
~VideoGDI() { term(); }
|
~VideoGDI() { term(); }
|
||||||
|
|
||||||
uint32_t* buffer = nullptr;
|
struct Device {
|
||||||
HBITMAP bitmap = nullptr;
|
HBITMAP bitmap = nullptr;
|
||||||
HDC bitmapdc = nullptr;
|
HDC dc = nullptr;
|
||||||
BITMAPINFO bmi;
|
BITMAPINFO info = {};
|
||||||
|
} device;
|
||||||
|
|
||||||
struct {
|
struct Settings {
|
||||||
HWND handle = nullptr;
|
HWND handle = nullptr;
|
||||||
|
|
||||||
unsigned width = 0;
|
uint32_t* buffer = nullptr;
|
||||||
unsigned height = 0;
|
uint width = 0;
|
||||||
|
uint height = 0;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
@@ -34,12 +36,38 @@ struct VideoGDI : Video {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
settings.width = width;
|
if(!settings.buffer || settings.width != width || settings.height != height) {
|
||||||
settings.height = height;
|
if(settings.buffer) {
|
||||||
|
delete] settings.buffer;
|
||||||
|
DeleteObject(device.bitmap);
|
||||||
|
DeleteObject(device.dc);
|
||||||
|
}
|
||||||
|
settings.buffer = new uint32_t[width * height]();
|
||||||
|
settings.width = width;
|
||||||
|
settings.height = height;
|
||||||
|
|
||||||
pitch = 1024 * 4;
|
HDC hdc = GetDC(settings.handle);
|
||||||
return data = buffer;
|
device.dc = CreateCompatibleDC(hdc);
|
||||||
|
assert(device.dc);
|
||||||
|
device.bitmap = CreateCompatibleBitmap(hdc, width, height);
|
||||||
|
assert(device.bitmap);
|
||||||
|
SelectObject(device.dc, device.bitmap);
|
||||||
|
ReleaseDC(settings.handle, hdc);
|
||||||
|
|
||||||
|
memory::fill(&device.info, sizeof(BITMAPINFO));
|
||||||
|
device.info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
device.info.bmiHeader.biWidth = width;
|
||||||
|
device.info.bmiHeader.biHeight = -height;
|
||||||
|
device.info.bmiHeader.biPlanes = 1;
|
||||||
|
device.info.bmiHeader.biBitCount = 32;
|
||||||
|
device.info.bmiHeader.biCompression = BI_RGB;
|
||||||
|
device.info.bmiHeader.biSizeImage = width * height * sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = settings.buffer;
|
||||||
|
pitch = settings.width * sizeof(uint32_t);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unlock() -> void {}
|
auto unlock() -> void {}
|
||||||
@@ -50,40 +78,26 @@ struct VideoGDI : Video {
|
|||||||
RECT rc;
|
RECT rc;
|
||||||
GetClientRect(settings.handle, &rc);
|
GetClientRect(settings.handle, &rc);
|
||||||
|
|
||||||
SetDIBits(bitmapdc, bitmap, 0, settings.height, (void*)buffer, &bmi, DIB_RGB_COLORS);
|
SetDIBits(device.dc, device.bitmap, 0, settings.height, (void*)settings.buffer, &device.info, DIB_RGB_COLORS);
|
||||||
HDC hdc = GetDC(settings.handle);
|
HDC hdc = GetDC(settings.handle);
|
||||||
StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, bitmapdc, 0, 1024 - settings.height, settings.width, settings.height, SRCCOPY);
|
StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, device.dc, 0, -settings.height, settings.width, settings.height, SRCCOPY);
|
||||||
ReleaseDC(settings.handle, hdc);
|
ReleaseDC(settings.handle, hdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto init() -> bool {
|
auto init() -> bool {
|
||||||
buffer = (uint32_t*)memory::allocate(1024 * 1024 * sizeof(uint32_t));
|
settings.width = 0;
|
||||||
|
settings.height = 0;
|
||||||
HDC hdc = GetDC(settings.handle);
|
|
||||||
bitmapdc = CreateCompatibleDC(hdc);
|
|
||||||
assert(bitmapdc);
|
|
||||||
bitmap = CreateCompatibleBitmap(hdc, 1024, 1024);
|
|
||||||
assert(bitmap);
|
|
||||||
SelectObject(bitmapdc, bitmap);
|
|
||||||
ReleaseDC(settings.handle, hdc);
|
|
||||||
|
|
||||||
memset(&bmi, 0, sizeof(BITMAPINFO));
|
|
||||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
||||||
bmi.bmiHeader.biWidth = 1024;
|
|
||||||
bmi.bmiHeader.biHeight = -1024;
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biBitCount = 32; //biBitCount of 15 is invalid, biBitCount of 16 is really RGB555
|
|
||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint32_t);
|
|
||||||
|
|
||||||
settings.width = 256;
|
|
||||||
settings.height = 256;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto term() -> void {
|
auto term() -> void {
|
||||||
DeleteObject(bitmap);
|
if(settings.buffer) {
|
||||||
DeleteDC(bitmapdc);
|
delete[] settings.buffer;
|
||||||
if(buffer) { memory::free(buffer); buffer = nullptr; }
|
DeleteObject(device.bitmap);
|
||||||
|
DeleteDC(device.dc);
|
||||||
|
settings.buffer = nullptr;
|
||||||
|
device.bitmap = nullptr;
|
||||||
|
device.dc = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -13,25 +13,25 @@ struct VideoXShm : Video {
|
|||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
Display* display = nullptr;
|
Display* display = nullptr;
|
||||||
signed screen = 0;
|
int screen = 0;
|
||||||
signed depth = 0;
|
int depth = 0;
|
||||||
Visual* visual = nullptr;
|
Visual* visual = nullptr;
|
||||||
Window window = 0;
|
Window window = 0;
|
||||||
|
|
||||||
XShmSegmentInfo shmInfo;
|
XShmSegmentInfo shmInfo;
|
||||||
XImage* image = nullptr;
|
XImage* image = nullptr;
|
||||||
uint32_t* buffer = nullptr;
|
uint32_t* buffer = nullptr;
|
||||||
unsigned width = 0;
|
uint width = 0;
|
||||||
unsigned height = 0;
|
uint height = 0;
|
||||||
} device;
|
} device;
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
uintptr_t handle = 0;
|
uintptr_t handle = 0;
|
||||||
unsigned filter = Video::FilterLinear;
|
uint filter = Video::FilterLinear;
|
||||||
|
|
||||||
uint32_t* buffer = nullptr;
|
uint32_t* buffer = nullptr;
|
||||||
unsigned width = 0;
|
uint width = 0;
|
||||||
unsigned height = 0;
|
uint height = 0;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
@@ -51,15 +51,15 @@ struct VideoXShm : Video {
|
|||||||
settings.handle = value.get<uintptr_t>();
|
settings.handle = value.get<uintptr_t>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(name == Video::Filter && value.is<unsigned>()) {
|
if(name == Video::Filter && value.is<uint>()) {
|
||||||
settings.filter = value.get<unsigned>();
|
settings.filter = value.get<uint>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
if(settings.buffer == nullptr || settings.width != width || settings.height != height) {
|
if(!settings.buffer || settings.width != width || settings.height != height) {
|
||||||
if(settings.buffer) delete[] settings.buffer;
|
if(settings.buffer) delete[] settings.buffer;
|
||||||
settings.width = width, settings.height = height;
|
settings.width = width, settings.height = height;
|
||||||
settings.buffer = new uint32_t[width * height + 16]; //+16 is padding for linear interpolation
|
settings.buffer = new uint32_t[width * height + 16]; //+16 is padding for linear interpolation
|
||||||
@@ -74,36 +74,36 @@ struct VideoXShm : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto clear() -> void {
|
auto clear() -> void {
|
||||||
if(settings.buffer == nullptr) return;
|
if(!settings.buffer) return;
|
||||||
uint32_t* dp = settings.buffer;
|
uint32_t* dp = settings.buffer;
|
||||||
unsigned length = settings.width * settings.height;
|
uint length = settings.width * settings.height;
|
||||||
while(length--) *dp++ = 255u << 24;
|
while(length--) *dp++ = 255u << 24;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto refresh() -> void {
|
auto refresh() -> void {
|
||||||
if(settings.buffer == nullptr) return;
|
if(!settings.buffer) return;
|
||||||
size();
|
size();
|
||||||
|
|
||||||
float xratio = (float)settings.width / (float)device.width;
|
float xratio = (float)settings.width / (float)device.width;
|
||||||
float yratio = (float)settings.height / (float)device.height;
|
float yratio = (float)settings.height / (float)device.height;
|
||||||
|
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
for(unsigned y = 0; y < device.height; y++) {
|
for(uint y = 0; y < device.height; y++) {
|
||||||
float ystep = y * yratio;
|
float ystep = y * yratio;
|
||||||
float xstep = 0;
|
float xstep = 0;
|
||||||
|
|
||||||
uint32_t* sp = settings.buffer + (unsigned)ystep * settings.width;
|
uint32_t* sp = settings.buffer + (uint)ystep * settings.width;
|
||||||
uint32_t* dp = device.buffer + y * device.width;
|
uint32_t* dp = device.buffer + y * device.width;
|
||||||
|
|
||||||
if(settings.filter == Video::FilterNearest) {
|
if(settings.filter == Video::FilterNearest) {
|
||||||
for(unsigned x = 0; x < device.width; x++) {
|
for(uint x = 0; x < device.width; x++) {
|
||||||
*dp++ = 255u << 24 | sp[(unsigned)xstep];
|
*dp++ = 255u << 24 | sp[(uint)xstep];
|
||||||
xstep += xratio;
|
xstep += xratio;
|
||||||
}
|
}
|
||||||
} else { //settings.filter == Video::FilterLinear
|
} else { //settings.filter == Video::FilterLinear
|
||||||
for(unsigned x = 0; x < device.width; x++) {
|
for(uint x = 0; x < device.width; x++) {
|
||||||
*dp++ = 255u << 24 | interpolate(xstep - (unsigned)xstep, sp[(unsigned)xstep], sp[(unsigned)xstep + 1]);
|
*dp++ = 255u << 24 | interpolate(xstep - (uint)xstep, sp[(uint)xstep], sp[(uint)xstep + 1]);
|
||||||
xstep += xratio;
|
xstep += xratio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ struct VideoXShm : Video {
|
|||||||
XNextEvent(device.display, &event);
|
XNextEvent(device.display, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(size() == false) return false;
|
if(!size()) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto free() -> void {
|
auto free() -> void {
|
||||||
if(device.buffer == nullptr) return;
|
if(!device.buffer) return;
|
||||||
device.buffer = nullptr;
|
device.buffer = nullptr;
|
||||||
XShmDetach(device.display, &device.shmInfo);
|
XShmDetach(device.display, &device.shmInfo);
|
||||||
XDestroyImage(device.image);
|
XDestroyImage(device.image);
|
||||||
|
Reference in New Issue
Block a user