Update to v094 release.

byuu says:

This release adds support for game libraries, and substantially improves
Game Boy and Game Boy Color emulation with cycle-based renderers. Many
other changes are also present.

It's very important to note that this release now defaults to optimal
drivers rather than safe drivers. This is particularly important if you
do not have strong OpenGL 3.2 drivers. If performance is bad, go to
Settings -> Configuration -> Advanced, change the video driver, and
restart higan. In the rare case that you have trouble opening higan, you
can edit settings.bml directly and change the setting there. The Windows
safe driver is Direct3D, and the Linux safe driver is XShm.

Also note that although display emulation shaders are now supported,
they have not been included in this release as they are not ready yet.
The support has been built-in anyway, so that they can be tested by
everyone. Once refined, future releases of higan will come with built-in
shaders for each emulated system that simulates the unique display
characteristics of each.

Changelog (since v093):
- sfc: added SA-1 MDR support (fixes SD Gundam G-Next bug)
- sfc: remove random/ and config/, merge to system/ with better
  randomization
- gb: improved color emulation palette contrast
- gbc: do not sort sprites by X-priority
- gbc: allow transparency on BG priority pixels
- gbc: VRAM DMA timing and register fixes
- gbc: block invalid VRAM DMA transfer source and target addresses
- gba: added LCD color emulation (without it, colors are grossly
  over-saturated)
- gba: removed internal frame blending (use shaders to simulate motion
  blur if desired)
- gba: added Game Boy Player support (adds joypad rumble support to
  supported games)
- gba: SOUND_CTL_H is readable
- gb/gbc: PPU renderer is now cycle-based (major accuracy improvement)
- gb/gbc: OAM DMA runs in parallel with the CPU
- gb/gbc: only HRAM can be accessed during OAM DMA
- gb/gbc: fixed serialization of games with SRAM
- gb/gbc: disallow up+down or left+right at the same time
- gb/gbc: added weak hipass filter to remove DC bias
- gb/gbc: STAT OAM+Hblank IRQs only trigger during active display
- gb/gbc: fixed underflow in window clamping
- gb/gbc/gba: audio mixes internally at 2MHz now instead of 4MHz (does
  not affect accuracy)
- gb/gbc/gba: audio volume reduced for consistency with other systems
- fc/sfc/gb/gbc/gba: cheat codes are now stored in universal, decrypted
  format
- ethos: replaced file loader with a proper game library
- ethos: added display emulation shader support
- ethos: added color emulation option to video settings
- ethos: program icon upgraded from 48x48 to 512x512
- ethos: settings and tools windows now use tab frames (less wasted
  screen space)
- ethos: default to optimal (video, audio, input) drivers instead of
  safest drivers
- ethos: input mapping system completely rewritten to support
  hotplugging and unique device mappings
- ruby: added fixes for OpenGL 3.2 on AMD graphics cards
- ruby: quark shaders now support user settings inside of manifest
- ruby: quark shaders can use integral textures (allows display
  emulation shaders to work with raw colors)
- ruby: add joypad rumble support
- ruby: XInput (Xbox 360) controllers now support hotplugging
- ruby: added Linux udev joypad driver with hotplug support
- phoenix: fixed a rare null pointer dereference issue on Windows
- port: target -std=c++11 instead of -std=gnu++11 (do not rely on GNU
  C++ extensions)
- port: added out-of-the-box compilation support for BSD/Clang 3.3+
- port: applied a few Debian upstream patches
- cheats: updated to mightymo's 2014-01-02 release; decrypted all Game
  Genie codes
This commit is contained in:
Tim Allen 2014-01-20 19:55:17 +11:00
parent fe85679321
commit 10464b8c54
22 changed files with 9306 additions and 9255 deletions

View File

@ -21,6 +21,7 @@ resource: force
clean:
-@$(call delete,obj/*.o)
-@$(call delete,*.dll)
-@$(call delete,*.so)
install: uninstall

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "093.13";
static const char Version[] = "094";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";

View File

@ -70,12 +70,15 @@ struct image {
//fill.hpp
inline void fill(uint64_t color = 0);
inline void linearGradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d);
inline void horizontalGradient(uint64_t a, uint64_t b);
inline void verticalGradient(uint64_t a, uint64_t b);
inline void gradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d);
inline void gradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY, function<double (double, double)> callback);
inline void crossGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void diamondGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void horizontalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY);
inline void radialGradient(uint64_t a, uint64_t b);
inline void sphericalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void squareGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
inline void verticalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY);
//scale.hpp
inline void scale(unsigned width, unsigned height, bool linear = true);

View File

@ -14,7 +14,7 @@ void image::fill(uint64_t color) {
}
}
void image::linearGradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) {
void image::gradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) {
for(unsigned y = 0; y < height; y++) {
uint8_t* dp = data + pitch * y;
double muY = (double)y / (double)height;
@ -26,35 +26,61 @@ void image::linearGradient(uint64_t a, uint64_t b, uint64_t c, uint64_t d) {
}
}
void image::horizontalGradient(uint64_t a, uint64_t b) {
linearGradient(a, b, a, b);
}
void image::verticalGradient(uint64_t a, uint64_t b) {
linearGradient(a, a, b, b);
}
void image::radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
if(radiusX < 1) radiusX = width >> 1;
if(radiusY < 1) radiusY = height >> 1;
void image::gradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY, function<double (double, double)> callback) {
for(signed y = 0; y < height; y++) {
uint8_t* dp = data + pitch * y;
double py = max(-radiusY, min(+radiusY, y - centerY)) * 1.0 / radiusY;
for(signed x = 0; x < width; x++) {
double px = max(-radiusX, min(+radiusX, x - centerX)) * 1.0 / radiusX;
double mu = min(1.0, sqrt(px * px + py * py));
double mu = max(0.0, min(1.0, callback(px, py)));
if(mu != mu) mu = 1.0; //NaN
write(dp, interpolate4f(a, b, mu));
dp += stride;
}
}
}
void image::radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY) {
radialGradient(a, b, radiusX, radiusY, width >> 1, height >> 1);
void image::crossGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
x = fabs(x), y = fabs(y);
return min(x, y) * min(x, y);
});
}
void image::radialGradient(uint64_t a, uint64_t b) {
radialGradient(a, b, width >> 1, height >> 1, width >> 1, height >> 1);
void image::diamondGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return fabs(x) + fabs(y);
});
}
void image::horizontalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return fabs(x);
});
}
void image::radialGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return sqrt(x * x + y * y);
});
}
void image::sphericalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return x * x + y * y;
});
}
void image::squareGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return max(fabs(x), fabs(y));
});
}
void image::verticalGradient(uint64_t a, uint64_t b, signed radiusX, signed radiusY, signed centerX, signed centerY) {
return gradient(a, b, radiusX, radiusY, centerX, centerY, [](double x, double y) -> double {
return fabs(y);
});
}
}

View File

@ -174,7 +174,7 @@ void pCanvas::rasterize() {
if(canvas.state.mode == Canvas::Mode::Gradient) {
nall::image image;
image.allocate(width, height);
image.linearGradient(
image.gradient(
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
);
memcpy(target, image.data, image.size);

View File

@ -131,7 +131,7 @@ void pCanvas::rasterize() {
if(canvas.state.mode == Canvas::Mode::Gradient) {
nall::image image;
image.allocate(width, height);
image.linearGradient(
image.gradient(
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
);
memcpy(buffer, image.data, image.size);

View File

@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp'
**
** Created: Sun Jan 5 03:02:03 2014
** Created: Mon Jan 20 01:11:54 2014
** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2)
**
** WARNING! All changes made in this file will be lost!

View File

@ -67,7 +67,7 @@ void pCanvas::rasterize() {
if(canvas.state.mode == Canvas::Mode::Gradient) {
nall::image image;
image.allocate(width, height);
image.linearGradient(
image.gradient(
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
);
memcpy(surface->bits(), image.data, image.size);

View File

@ -2,7 +2,6 @@ namespace phoenix {
static bool Application_keyboardProc(HWND, UINT, WPARAM, LPARAM);
static void Application_processDialogMessage(MSG&);
static void Application_processMessageQueue();
static LRESULT CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM);
void pApplication::run() {
@ -39,24 +38,13 @@ void Application_processDialogMessage(MSG& msg) {
|| msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) {
if(Application_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) {
DispatchMessage(&msg);
return Application_processMessageQueue();
return;
}
}
if(!IsDialogMessage(GetForegroundWindow(), &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
Application_processMessageQueue();
}
}
static void Application_processMessageQueue() {
while(!messageQueue.empty()) {
Message message = messageQueue.takeFirst();
if(message.type == Message::Type::ListView_OnActivate) {
ListView* listView = (ListView*)message.object;
if(listView->onActivate) listView->onActivate();
}
}
}

View File

@ -1,16 +1,12 @@
namespace phoenix {
typedef LRESULT CALLBACK (*WindowProc)(HWND, UINT, WPARAM, LPARAM);
struct Message {
enum class Type : unsigned {
ListView_OnActivate,
struct AppMessage {
enum : unsigned {
ListView_onActivate = 0,
};
Type type;
Object* object;
};
static vector<Message> messageQueue;
typedef LRESULT CALLBACK (*WindowProc)(HWND, UINT, WPARAM, LPARAM);
struct pApplication {
static void run();

View File

@ -299,6 +299,12 @@ static LRESULT CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT
break;
}
case WM_APP + AppMessage::ListView_onActivate: {
ListView* listView = (ListView*)lparam;
if(listView && listView->onActivate) listView->onActivate();
break;
}
case WM_HSCROLL:
case WM_VSCROLL: {
Object* object = nullptr;

View File

@ -168,7 +168,7 @@ void pCanvas::rasterize() {
if(canvas.state.mode == Canvas::Mode::Gradient) {
nall::image image;
image.allocate(width, height);
image.linearGradient(
image.gradient(
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
);
memcpy(surface, image.data, image.size);

View File

@ -214,7 +214,7 @@ void pListView::onActivate(LPARAM lparam) {
if(listView.state.text.empty() || !listView.state.selected) return;
//LVN_ITEMACTIVATE is not re-entrant until DispatchMessage() completes
//if(listView.onActivate) listView.onActivate();
messageQueue.append({Message::Type::ListView_OnActivate, (Object*)&listView});
PostMessage(parentHwnd, WM_APP + AppMessage::ListView_onActivate, 0, (LPARAM)&listView);
}
void pListView::onChange(LPARAM lparam) {

View File

@ -17,5 +17,5 @@ vec2 radialDistortion(vec2 coord) {
}
void main() {
fragColor = texture2D(source[0], radialDistortion(texCoord));
fragColor = texture(source[0], radialDistortion(texCoord));
}

View File

@ -17,8 +17,8 @@ void main() {
vec2 offset = fract(texCoord * sourceSize[0].xy) - 0.5;
offset /= sourceSize[0].xy;
vec3 cx = texture2D(source[0], texCoord - offset).xyz;
vec3 cy = texture2D(source[0], texCoord).xyz;
vec3 cx = texture(source[0], texCoord - offset).xyz;
vec3 cy = texture(source[0], texCoord).xyz;
vec3 cz = vec3(5.0 * grayscale(abs(cx - cy)));
fragColor = vec4(clamp(cz, 0.0, 1.0), 1.0);

View File

@ -9,7 +9,7 @@ in Vertex {
out vec4 fragColor;
void main() {
vec4 rgba = texture2D(source[0], texCoord);
vec4 rgba = texture(source[0], texCoord);
vec4 intensity;
if(fract(gl_FragCoord.y * (0.5 * 4.0 / 3.0)) > 0.5) {
intensity = vec4(0);

View File

@ -12,7 +12,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Toggle Mouse Capture";
hotkey->mapping = "KB0::F12";
hotkey->mapping = "1/Button/F12";
hotkey->press = [] {
input.acquired() ? input.unacquire() : input.acquire();
@ -22,7 +22,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Show Library";
hotkey->mapping = "KB0::L";
hotkey->mapping = "1/Button/L";
hotkey->press = [] {
libraryManager->show();
@ -32,7 +32,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Pause Emulation";
hotkey->mapping = "KB0::P";
hotkey->mapping = "1/Button/P";
hotkey->press = [] {
program->pause = !program->pause;
@ -42,7 +42,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Fast Forward";
hotkey->mapping = "KB0::Tilde";
hotkey->mapping = "1/Button/Tilde";
hotkey->press = [] {
video.set(Video::Synchronize, false);
@ -80,7 +80,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Save State";
hotkey->mapping = "KB0::F5";
hotkey->mapping = "1/Button/F5";
hotkey->press = [&] {
utility->saveState(activeSlot);
@ -90,7 +90,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Load State";
hotkey->mapping = "KB0::F7";
hotkey->mapping = "1/Button/F7";
hotkey->press = [&] {
utility->loadState(activeSlot);
@ -100,7 +100,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Decrement Slot";
hotkey->mapping = "KB0::F6";
hotkey->mapping = "1/Button/F6";
hotkey->press = [&] {
if(--activeSlot == 0) activeSlot = 5;
@ -111,7 +111,7 @@ void InputManager::appendHotkeys() {
{
auto hotkey = new HotkeyInput;
hotkey->name = "Increment Slot";
hotkey->mapping = "KB0::F8";
hotkey->mapping = "1/Button/F8";
hotkey->press = [&] {
if(++activeSlot == 6) activeSlot = 1;

View File

@ -185,6 +185,20 @@ HotkeyInput::HotkeyInput() {
//
//convert an input mapping string to a more human-readable form for the UI
string InputManager::sanitize(string mapping, string concatenate) const {
lstring values = mapping.split(",");
for(auto& value : values) {
lstring part = value.split("/");
if(part.size() < 2) continue; //skip "None" mapping
if(part[0] == "1") part[0] = "Keyboard";
else if(part[0] == "2") part[0] = "Mouse";
else part[0] = {"Joypad(", part[0].slice(0, 3), ")"};
value = part.merge(".");
}
return values.merge(concatenate);
}
void InputManager::onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
if(settings->focused()) {
inputSettings->inputEvent(device, group, input, oldValue, newValue);

View File

@ -51,6 +51,7 @@ struct InputManager {
vector<AbstractInput*> inputMap;
vector<HotkeyInput*> hotkeyMap;
string sanitize(string mapping, string concatenate) const;
void onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
HID::Device* findMouse();
void bind();

View File

@ -25,8 +25,7 @@ void HotkeySettings::synchronize() {
void HotkeySettings::refresh() {
unsigned index = 0;
for(auto& hotkey : inputManager->hotkeyMap) {
string mapping = hotkey->mapping;
mapping.replace(",", " and ");
string mapping = inputManager->sanitize(hotkey->mapping, " and ");
inputList.setText(index++, {hotkey->name, mapping});
}
synchronize();

View File

@ -121,8 +121,7 @@ void InputSettings::inputChanged() {
for(unsigned number : activeDevice().order) {
auto& input = activeDevice().input[number];
auto abstract = inputManager->inputMap(input.guid);
string mapping = abstract->mapping;
mapping.replace(",", " or ");
string mapping = inputManager->sanitize(abstract->mapping, " or ");
inputList.setText(index++, {input.name, mapping});
}
}