Update to v093r01 release.

byuu says:

Changelog:
- added SA-1 MDR; fixes bug in SD Gundam G-Next where the main
  battleship was unable to fire
- added out-of-the-box support for any BSD running Clang 3.3+ (FreeBSD
  10+, notably)
- added new video shader, "Display Emulation", which changes the shader
  based on the emulated system
- fixed the home button to go to your default library path
- phoenix: Windows port won't send onActivate unless an item is selected
  (prevents crashing on pressing enter in file dialog)
- ruby: removed vec4 position from out Vertex {} (helps AMD cards)
- shaders: updated all shaders to use texture() instead of texture2D()
  (helps AMD cards)

The "Display Emulation" option works like this: when selected, it tries
to load "<path>/Video Shaders/Emulation/<systemName>.shader/"; otherwise
it falls back to the blur shader. <path> is the usual (next to binary,
then in <config>/higan, then in /usr/share/higan, etc); and <systemName>
is "Famicom", "Super Famicom", "Game Boy", "Game Boy Color", "Game Boy
Advance"

To support BSD, I had to modify the $(platform) variable to
differentiate between Linux and BSD.
As such, the new $(platform) values are:
win -> windows
osx -> macosx
x -> linux or bsd

I am also checking uname -s instead of uname -a now. No reason to
potentially match the hostname to the wrong OS type.
This commit is contained in:
Tim Allen
2013-10-21 22:45:39 +11:00
parent 4e2eb23835
commit 66f136718e
23 changed files with 242 additions and 117 deletions

View File

@@ -29,13 +29,8 @@ else ifeq ($(pgo),optimize)
endif endif
# platform # platform
ifeq ($(platform),x) ifeq ($(platform),windows)
flags += -march=native ifeq ($(arch),x86)
link += -s -Wl,-export-dynamic -ldl -lX11 -lXext
else ifeq ($(platform),osx)
flags += -march=native
else ifeq ($(platform),win)
ifeq ($(arch),win32)
flags += -m32 flags += -m32
link += -m32 link += -m32
endif endif
@@ -46,6 +41,14 @@ else ifeq ($(platform),win)
endif endif
link += -s -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32 link += -s -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else ifeq ($(platform),macosx)
flags += -march=native
else ifeq ($(platform),linux)
flags += -march=native
link += -s -Wl,-export-dynamic -lX11 -lXext -ldl
else ifeq ($(platform),bsd)
flags += -march=native
link += -s -Wl,-export-dynamic -lX11 -lXext
else else
$(error unsupported platform.) $(error unsupported platform.)
endif endif

View File

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

View File

@@ -15,34 +15,40 @@
##### #####
ifeq ($(platform),) ifeq ($(platform),)
uname := $(shell uname -a) uname := $(shell uname -s)
ifeq ($(uname),) ifeq ($(uname),)
platform := win platform := windows
delete = del $(subst /,\,$1) delete = del $(subst /,\,$1)
else ifneq ($(findstring Windows,$(uname)),) else ifneq ($(findstring Windows,$(uname)),)
platform := win platform := windows
delete = del $(subst /,\,$1) delete = del $(subst /,\,$1)
else ifneq ($(findstring CYGWIN,$(uname)),) else ifneq ($(findstring CYGWIN,$(uname)),)
platform := win platform := windows
delete = del $(subst /,\,$1) delete = del $(subst /,\,$1)
else ifneq ($(findstring Darwin,$(uname)),) else ifneq ($(findstring Darwin,$(uname)),)
platform := osx platform := macosx
delete = rm -f $1
else ifneq ($(findstring BSD,$(uname)),)
platform := bsd
delete = rm -f $1 delete = rm -f $1
else else
platform := x platform := linux
delete = rm -f $1 delete = rm -f $1
endif endif
endif endif
ifeq ($(compiler),) ifeq ($(compiler),)
ifeq ($(platform),win) ifeq ($(platform),windows)
compiler := g++ compiler := g++
flags := flags :=
link := link :=
else ifeq ($(platform),osx) else ifeq ($(platform),macosx)
compiler := clang compiler := clang
flags := -w -stdlib=libc++ flags := -w -stdlib=libc++
link := -lc++ -lobjc link := -lc++ -lobjc
else ifeq ($(platform),bsd)
compiler := clang++
flags := -w
else else
compiler := g++-4.7 compiler := g++-4.7
flags := flags :=

View File

@@ -227,8 +227,8 @@ struct file {
static bool exists(const string& filename) { static bool exists(const string& filename) {
#if !defined(_WIN32) #if !defined(_WIN32)
struct stat64 data; struct stat data;
if(stat64(filename, &data) != 0) return false; if(stat(filename, &data) != 0) return false;
#else #else
struct __stat64 data; struct __stat64 data;
if(_wstat64(utf16_t(filename), &data) != 0) return false; if(_wstat64(utf16_t(filename), &data) != 0) return false;
@@ -239,8 +239,8 @@ struct file {
static uintmax_t size(const string& filename) { static uintmax_t size(const string& filename) {
#if !defined(_WIN32) #if !defined(_WIN32)
struct stat64 data; struct stat data;
stat64(filename, &data); stat(filename, &data);
#else #else
struct __stat64 data; struct __stat64 data;
_wstat64(utf16_t(filename), &data); _wstat64(utf16_t(filename), &data);
@@ -250,8 +250,8 @@ struct file {
static time_t timestamp(const string& filename, file::time mode = file::time::create) { static time_t timestamp(const string& filename, file::time mode = file::time::create) {
#if !defined(_WIN32) #if !defined(_WIN32)
struct stat64 data; struct stat data;
stat64(filename, &data); stat(filename, &data);
#else #else
struct __stat64 data; struct __stat64 data;
_wstat64(utf16_t(filename), &data); _wstat64(utf16_t(filename), &data);

View File

@@ -32,7 +32,7 @@ struct Intrinsics {
/* Platform detection */ /* Platform detection */
#if defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(linux) || defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define PLATFORM_X #define PLATFORM_X
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; } Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; }
#elif defined(__APPLE__) #elif defined(__APPLE__)

View File

@@ -153,7 +153,8 @@ public:
//list.hpp //list.hpp
struct lstring : vector<string> { struct lstring : vector<string> {
inline optional<unsigned> find(rstring) const; inline optional<unsigned> find(rstring) const;
inline string concatenate(const string&) const; inline string merge(const string&) const;
inline string concatenate(const string&) const; //deprecated
inline lstring& isort(); inline lstring& isort();
inline lstring& strip(); inline lstring& strip();
inline void append() {} inline void append() {}

View File

@@ -38,7 +38,14 @@ inline string evaluateExpression(Node* node) {
} }
inline int64_t evaluateInteger(Node* node) { inline int64_t evaluateInteger(Node* node) {
if(node->type == Node::Type::Literal) return nall::integer(node->literal); if(node->type == Node::Type::Literal) {
if(node->literal.beginswith("0b")) return nall::binary(node->literal);
if(node->literal.beginswith("0o")) return nall::octal(node->literal);
if(node->literal.beginswith("0x")) return nall::hex(node->literal);
if(node->literal.beginswith("%")) return nall::binary(node->literal);
if(node->literal.beginswith("$")) return nall::hex(node->literal);
return nall::integer(node->literal);
}
#define p(n) evaluateInteger(node->link[n]) #define p(n) evaluateInteger(node->link[n])
switch(node->type) { switch(node->type) {

View File

@@ -8,17 +8,19 @@ inline bool isLiteral(const char*& s) {
return (n >= 'A' && n <= 'Z') return (n >= 'A' && n <= 'Z')
|| (n >= 'a' && n <= 'z') || (n >= 'a' && n <= 'z')
|| (n >= '0' && n <= '9') || (n >= '0' && n <= '9')
|| n == '_' || n == '\"'; || (n == '%' || n == '$' || n == '_' || n == '.')
|| (n == '\'' || n == '\"');
} }
inline string literalNumber(const char*& s) { inline string literalNumber(const char*& s) {
const char* p = s; const char* p = s;
//binary //binary
if(p[0] == '0' && p[1] == 'b') { if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) {
p += 2; unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while(p[0] == '0' || p[0] == '1') p++; while(p[0] == '0' || p[0] == '1') p++;
if(p - s < 3) throw "invalid binary literal"; if(p - s <= prefix) throw "invalid binary literal";
string result = substr(s, 0, p - s); string result = substr(s, 0, p - s);
s = p; s = p;
return result; return result;
@@ -26,19 +28,21 @@ inline string literalNumber(const char*& s) {
//octal //octal
if(p[0] == '0' && p[1] == 'o') { if(p[0] == '0' && p[1] == 'o') {
p += 2; unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while(p[0] >= '0' && p[0] <= '7') p++; while(p[0] >= '0' && p[0] <= '7') p++;
if(p - s < 3) throw "invalid octal literal"; if(p - s <= prefix) throw "invalid octal literal";
string result = substr(s, 0, p - s); string result = substr(s, 0, p - s);
s = p; s = p;
return result; return result;
} }
//hex //hex
if(p[0] == '0' && p[1] == 'x') { if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) {
p += 2; unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while((p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++; while((p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
if(p - s < 3) throw "invalid hex literal"; if(p - s <= prefix) throw "invalid hex literal";
string result = substr(s, 0, p - s); string result = substr(s, 0, p - s);
s = p; s = p;
return result; return result;
@@ -61,10 +65,11 @@ inline string literalNumber(const char*& s) {
} }
inline string literalString(const char*& s) { inline string literalString(const char*& s) {
const char* p = s + 1; const char* p = s;
char escape = *p++;
while(p[0] && p[0] != '\"') p++; while(p[0] && p[0] != escape) p++;
if(*p++ != '\"') throw "unclosed string literal"; if(*p++ != escape) throw "unclosed string literal";
string result = substr(s, 0, p - s); string result = substr(s, 0, p - s);
s = p; s = p;
@@ -74,7 +79,7 @@ inline string literalString(const char*& s) {
inline string literalVariable(const char*& s) { inline string literalVariable(const char*& s) {
const char* p = s; const char* p = s;
while(p[0] == '_' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++; while(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++;
string result = substr(s, 0, p - s); string result = substr(s, 0, p - s);
s = p; s = p;
@@ -85,8 +90,9 @@ inline string literal(const char*& s) {
const char* p = s; const char* p = s;
if(p[0] >= '0' && p[0] <= '9') return literalNumber(s); if(p[0] >= '0' && p[0] <= '9') return literalNumber(s);
if(p[0] == '\"') return literalString(s); if(p[0] == '%' || p[0] == '$') return literalNumber(s);
if(p[0] == '_' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) return literalVariable(s); if(p[0] == '\'' || p[0] == '\"') return literalString(s);
if(p[0] == '_' || p[0] == '.' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) return literalVariable(s);
throw "invalid literal"; throw "invalid literal";
} }

View File

@@ -9,7 +9,7 @@ optional<unsigned> lstring::find(rstring key) const {
return false; return false;
} }
string lstring::concatenate(const string& separator) const { string lstring::merge(const string& separator) const {
string output; string output;
for(unsigned i = 0; i < size(); i++) { for(unsigned i = 0; i < size(); i++) {
output.append(operator[](i)); output.append(operator[](i));
@@ -18,6 +18,11 @@ string lstring::concatenate(const string& separator) const {
return output; return output;
} }
//deprecated: alias to merge()
string lstring::concatenate(const string& separator) const {
return merge(separator);
}
lstring& lstring::isort() { lstring& lstring::isort() {
nall::sort(pool, objectsize, [](const string& x, const string& y) { nall::sort(pool, objectsize, [](const string& x, const string& y) {
return istrcmp(x, y) < 0; return istrcmp(x, y) < 0;

View File

@@ -22,7 +22,7 @@ protected:
unsigned objectsize = 0; unsigned objectsize = 0;
public: public:
explicit operator bool() const { return pool; } explicit operator bool() const { return objectsize; }
T* data() { return pool + poolbase; } T* data() { return pool + poolbase; }
const T* data() const { return pool + poolbase; } const T* data() const { return pool + poolbase; }
@@ -136,6 +136,9 @@ public:
objectsize -= length; objectsize -= length;
} }
void removefirst() { return remove(0); }
void removelast() { return remove(~0u); }
T take(unsigned position = ~0u) { T take(unsigned position = ~0u) {
if(position == ~0u) position = objectsize - 1; if(position == ~0u) position = objectsize - 1;
T object = pool[poolbase + position]; T object = pool[poolbase + position];
@@ -143,6 +146,9 @@ public:
return object; return object;
} }
T takefirst() { return take(0); }
T takelast() { return take(~0u); }
void reverse() { void reverse() {
unsigned pivot = size() / 2; unsigned pivot = size() / 2;
for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) { for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) {

View File

@@ -1,4 +1,13 @@
ifeq ($(platform),x) ifeq ($(platform),)
phoenixflags = $(cppflags) $(flags) -DPHOENIX_REFERENCE
phoenixlink =
else ifeq ($(platform),windows)
phoenixflags = $(cppflags) $(flags) -DPHOENIX_WINDOWS
phoenixlink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
else ifeq ($(platform),macosx)
phoenixflags = $(objcppflags) $(flags) -DPHOENIX_COCOA
phoenixlink = -framework Cocoa -framework Carbon
else
ifeq ($(phoenix),) ifeq ($(phoenix),)
phoenix := gtk phoenix := gtk
endif endif
@@ -12,13 +21,4 @@ ifeq ($(platform),x)
phoenixflags = $(cppflags) $(flags) -DPHOENIX_QT `pkg-config --cflags QtCore QtGui` phoenixflags = $(cppflags) $(flags) -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink = `pkg-config --libs QtCore QtGui` phoenixlink = `pkg-config --libs QtCore QtGui`
endif endif
else ifeq ($(platform),osx)
phoenixflags = $(objcppflags) $(flags) -DPHOENIX_COCOA
phoenixlink = -framework Cocoa -framework Carbon
else ifeq ($(platform),win)
phoenixflags = $(cppflags) $(flags) -DPHOENIX_WINDOWS
phoenixlink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
else
phoenixflags = $(cppflags) $(flags) -DPHOENIX_REFERENCE
phoenixlink =
endif endif

View File

@@ -134,7 +134,9 @@ static bool Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
if(dynamic_cast<ListView*>(object)) { if(dynamic_cast<ListView*>(object)) {
ListView& listView = (ListView&)*object; ListView& listView = (ListView&)*object;
if(wparam == VK_RETURN) { if(wparam == VK_RETURN) {
if(listView.onActivate) listView.onActivate(); if(listView.state.text.size() && listView.selected()) {
if(listView.onActivate) listView.onActivate();
}
} }
} else if(dynamic_cast<LineEdit*>(object)) { } else if(dynamic_cast<LineEdit*>(object)) {
LineEdit& lineEdit = (LineEdit&)*object; LineEdit& lineEdit = (LineEdit&)*object;
@@ -369,7 +371,9 @@ static LRESULT CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wpara
if(listView.p.locked == false && listView.onChange) listView.onChange(); if(listView.p.locked == false && listView.onChange) listView.onChange();
} }
} else if(nmhdr->code == LVN_ITEMACTIVATE) { } else if(nmhdr->code == LVN_ITEMACTIVATE) {
if(listView.onActivate) listView.onActivate(); if(listView.state.text.size() && listView.selected()) {
if(listView.onActivate) listView.onActivate();
}
} else if(nmhdr->code == NM_CUSTOMDRAW) { } else if(nmhdr->code == NM_CUSTOMDRAW) {
LPNMLVCUSTOMDRAW lvcd = (LPNMLVCUSTOMDRAW)nmhdr; LPNMLVCUSTOMDRAW lvcd = (LPNMLVCUSTOMDRAW)nmhdr;
switch(lvcd->nmcd.dwDrawStage) { switch(lvcd->nmcd.dwDrawStage) {

View File

@@ -1,4 +1,4 @@
ifeq ($(platform),osx) ifeq ($(platform),macosx)
rubyflags = $(objcppflags) $(flags) rubyflags = $(objcppflags) $(flags)
else else
rubyflags = $(cppflags) $(flags) rubyflags = $(cppflags) $(flags)
@@ -28,10 +28,10 @@ rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`) rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
ifeq ($(platform),x) ifeq ($(platform),windows)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32) rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
else ifeq ($(platform),macosx)
rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
endif endif

View File

@@ -84,15 +84,12 @@ public:
DWORD pos, size; DWORD pos, size;
void* output; void* output;
if(settings.synchronize == true) { if(settings.synchronize) {
//wait until playback buffer has an empty ring to write new audio data to //wait until playback buffer has an empty ring to write new audio data to
while(device.distance >= device.rings - 1) { while(device.distance >= device.rings - 1) {
dsb_b->GetCurrentPosition(&pos, 0); dsb_b->GetCurrentPosition(&pos, 0);
unsigned activering = pos / (device.latency * 4); unsigned activering = pos / (device.latency * 4);
if(activering == device.readring) { if(activering == device.readring) continue;
if(settings.synchronize == false) Sleep(1);
continue;
}
//subtract number of played rings from ring distance counter //subtract number of played rings from ring distance counter
device.distance -= (device.rings + activering - device.readring) % device.rings; device.distance -= (device.rings + activering - device.readring) % device.rings;

View File

@@ -2,6 +2,9 @@ void OpenGL::shader(const char* pathname) {
for(auto& program : programs) program.release(); for(auto& program : programs) program.release();
programs.reset(); programs.reset();
for(auto& frame : frames) glDeleteTextures(1, &frame.texture);
frames.reset();
format = GL_RGBA8; format = GL_RGBA8;
filter = GL_LINEAR; filter = GL_LINEAR;
wrap = GL_CLAMP_TO_BORDER; wrap = GL_CLAMP_TO_BORDER;
@@ -15,10 +18,24 @@ void OpenGL::shader(const char* pathname) {
programs(n).bind(this, node, pathname); programs(n).bind(this, node, pathname);
} }
bind(this, document["output"], pathname); bind(document, pathname);
OpenGLProgram::bind(this, document["output"], pathname);
} else {
//no shader; assign default values
history.length = 0;
history.format = GL_RGBA8;
history.filter = GL_LINEAR;
history.wrap = GL_CLAMP_TO_BORDER;
} }
} }
void OpenGL::bind(const Markup::Node& node, const string& pathname) {
history.length = node["history/frames"].decimal();
if(node["history/format"].exists()) history.format = glrFormat(node["history/format"].text());
if(node["history/filter"].exists()) history.filter = glrFilter(node["history/filter"].text());
if(node["history/wrap"].exists()) history.wrap = glrWrap(node["history/wrap"].text());
}
bool OpenGL::lock(uint32_t*& data, unsigned& pitch) { bool OpenGL::lock(uint32_t*& data, unsigned& pitch) {
pitch = width * sizeof(uint32_t); pitch = width * sizeof(uint32_t);
return data = buffer; return data = buffer;
@@ -40,19 +57,30 @@ void OpenGL::clear() {
void OpenGL::refresh() { void OpenGL::refresh() {
clear(); clear();
//frame[] must always contain max# of previous frames: allocate them now, so first few frames can use them
while(frames.size() < history.length) {
OpenGLTexture frame;
glGenTextures(1, &frame.texture);
glBindTexture(GL_TEXTURE_2D, frame.texture);
glTexImage2D(GL_TEXTURE_2D, 0, frame.format = history.format, frame.width = width, frame.height = height, 0, GL_BGRA, inputFormat, buffer);
frame.filter = history.filter;
frame.wrap = history.wrap;
frames.append(frame);
}
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, inputFormat, buffer); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, inputFormat, buffer);
struct History { struct Source {
GLuint texture; GLuint texture;
unsigned width, height; unsigned width, height;
GLuint filter, wrap; GLuint filter, wrap;
}; };
vector<History> history; vector<Source> sources;
unsigned sourceWidth = width, sourceHeight = height; unsigned sourceWidth = width, sourceHeight = height;
history.prepend({texture, sourceWidth, sourceHeight, filter, wrap}); sources.prepend({texture, sourceWidth, sourceHeight, filter, wrap});
for(auto& p : programs) { for(auto& p : programs) {
unsigned targetWidth = p.absoluteWidth ? p.absoluteWidth : outputWidth; unsigned targetWidth = p.absoluteWidth ? p.absoluteWidth : outputWidth;
@@ -65,29 +93,35 @@ void OpenGL::refresh() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer);
glrUniform1i("phase", p.phase); glrUniform1i("phase", p.phase);
glrUniform1i("sourceLength", history.size()); glrUniform1i("frameLength", frames.size());
glrUniform1i("sourceLength", sources.size());
glrUniform1i("pixmapLength", p.pixmaps.size()); glrUniform1i("pixmapLength", p.pixmaps.size());
glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight); glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight);
glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight); glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
//glrUniform4f("targetActualSize", glrSize(targetWidth), glrSize(targetHeight), 1.0 / glrSize(targetWidth), 1.0 / glrSize(targetHeight));
//glrUniform4f("outputActualSize", glrSize(outputWidth), glrSize(outputHeight), 1.0 / glrSize(outputWidth), 1.0 / glrSize(outputHeight));
unsigned aid = 0; unsigned aid = 0;
for(auto& pixmap : history) { for(auto& frame : frames) {
glrUniform1i({"source[", aid, "]"}, aid); glrUniform1i({"frame[", aid, "]"}, aid);
glrUniform4f({"sourceSize[", aid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height); glrUniform4f({"frameSize[", aid, "]"}, frame.width, frame.height, 1.0 / frame.width, 1.0 / frame.height);
//glrUniform4f({"sourceActualSize[", aid, "]"}, glrSize(pixmap.width), glrSize(pixmap.height), 1.0 / glrSize(pixmap.width), 1.0 / glrSize(pixmap.height));
glActiveTexture(GL_TEXTURE0 + (aid++)); glActiveTexture(GL_TEXTURE0 + (aid++));
glBindTexture(GL_TEXTURE_2D, pixmap.texture); glBindTexture(GL_TEXTURE_2D, frame.texture);
glrParameters(pixmap.filter, pixmap.wrap); glrParameters(frame.filter, frame.wrap);
} }
unsigned bid = 0; unsigned bid = 0;
for(auto& pixmap : p.pixmaps) { for(auto& source : sources) {
glrUniform1i({"pixmap[", bid, "]"}, aid + bid); glrUniform1i({"source[", bid, "]"}, aid + bid);
glrUniform4f({"pixmapSize[", bid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height); glrUniform4f({"sourceSize[", bid, "]"}, source.width, source.height, 1.0 / source.width, 1.0 / source.height);
//glrUniform4f({"pixmapActualSize[", bid, "]"}, glrSize(pixmap.width), glrSize(pixmap.height), 1.0 / glrSize(pixmap.width), 1.0 / glrSize(pixmap.height));
glActiveTexture(GL_TEXTURE0 + aid + (bid++)); glActiveTexture(GL_TEXTURE0 + aid + (bid++));
glBindTexture(GL_TEXTURE_2D, source.texture);
glrParameters(source.filter, source.wrap);
}
unsigned cid = 0;
for(auto& pixmap : p.pixmaps) {
glrUniform1i({"pixmap[", cid, "]"}, aid + bid + cid);
glrUniform4f({"pixmapSize[", bid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height);
glActiveTexture(GL_TEXTURE0 + aid + bid + (cid++));
glBindTexture(GL_TEXTURE_2D, pixmap.texture); glBindTexture(GL_TEXTURE_2D, pixmap.texture);
glrParameters(pixmap.filter, pixmap.wrap); glrParameters(pixmap.filter, pixmap.wrap);
} }
@@ -99,7 +133,7 @@ void OpenGL::refresh() {
p.phase = (p.phase + 1) % p.modulo; p.phase = (p.phase + 1) % p.modulo;
sourceWidth = p.width, sourceHeight = p.height; sourceWidth = p.width, sourceHeight = p.height;
history.prepend({p.texture, sourceWidth, sourceHeight, p.filter, p.wrap}); sources.prepend({p.texture, sourceWidth, sourceHeight, p.filter, p.wrap});
} }
unsigned targetWidth = absoluteWidth ? absoluteWidth : outputWidth; unsigned targetWidth = absoluteWidth ? absoluteWidth : outputWidth;
@@ -116,6 +150,19 @@ void OpenGL::refresh() {
glrParameters(filter, wrap); glrParameters(filter, wrap);
render(sourceWidth, sourceHeight, outputWidth, outputHeight); render(sourceWidth, sourceHeight, outputWidth, outputHeight);
if(frames.size() > 0) {
OpenGLTexture frame = frames.take();
glBindTexture(GL_TEXTURE_2D, frame.texture);
if(width == frame.width && height == frame.height) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, inputFormat, buffer);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, frame.format, frame.width = width, frame.height = height, 0, GL_BGRA, inputFormat, buffer);
}
frames.prepend(frame);
}
} }
bool OpenGL::init() { bool OpenGL::init() {
@@ -142,6 +189,7 @@ bool OpenGL::init() {
} }
void OpenGL::term() { void OpenGL::term() {
shader(nullptr); //release shader resources (eg frame[] history)
OpenGLSurface::release(); OpenGLSurface::release();
if(buffer) { delete[] buffer; buffer = nullptr; } if(buffer) { delete[] buffer; buffer = nullptr; }
} }

View File

@@ -62,12 +62,20 @@ struct OpenGLProgram : OpenGLSurface {
struct OpenGL : OpenGLProgram { struct OpenGL : OpenGLProgram {
vector<OpenGLProgram> programs; vector<OpenGLProgram> programs;
vector<OpenGLTexture> frames;
struct History {
unsigned length = 0;
GLuint format = GL_RGBA8;
GLuint filter = GL_LINEAR;
GLuint wrap = GL_CLAMP_TO_BORDER;
} history;
GLuint inputFormat = GL_UNSIGNED_INT_8_8_8_8_REV; GLuint inputFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
unsigned outputWidth = 0; unsigned outputWidth = 0;
unsigned outputHeight = 0; unsigned outputHeight = 0;
void shader(const char* pathname); void shader(const char* pathname);
void bind(const Markup::Node& node, const string& pathname);
bool lock(uint32_t*& data, unsigned& pitch); bool lock(uint32_t*& data, unsigned& pitch);
void clear(); void clear();
void refresh(); void refresh();

View File

@@ -7,7 +7,6 @@ static string OpenGLOutputVertexShader = R"(
in vec2 texCoord; in vec2 texCoord;
out Vertex { out Vertex {
vec4 position;
vec2 texCoord; vec2 texCoord;
} vertexOut; } vertexOut;
@@ -42,7 +41,6 @@ static string OpenGLVertexShader = R"(
in vec2 texCoord; in vec2 texCoord;
out Vertex { out Vertex {
vec4 position;
vec2 texCoord; vec2 texCoord;
} vertexOut; } vertexOut;

View File

@@ -36,6 +36,9 @@ uint8 SA1::bus_read(unsigned addr) {
synchronize_cpu(); synchronize_cpu();
return bitmap_read(addr & 0x0fffff); return bitmap_read(addr & 0x0fffff);
} }
//unmapped region
return regs.mdr;
} }
void SA1::bus_write(unsigned addr, uint8 data) { void SA1::bus_write(unsigned addr, uint8 data) {
@@ -116,7 +119,7 @@ uint8 SA1::op_read(unsigned addr) {
void SA1::op_write(unsigned addr, uint8 data) { void SA1::op_write(unsigned addr, uint8 data) {
tick(); tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick(); if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
bus_write(addr, data); bus_write(addr, regs.mdr = data);
} }
uint8 SA1::mmcrom_read(unsigned addr) { uint8 SA1::mmcrom_read(unsigned addr) {

View File

@@ -11,21 +11,25 @@ include gba/Makefile
ui_objects := ui-ethos ui-configuration ui-interface ui-utility ui_objects := ui-ethos ui-configuration ui-interface ui-utility
ui_objects += ui-input ui-window ui-general ui-settings ui-tools ui_objects += ui-input ui-window ui-general ui-settings ui-tools
ui_objects += phoenix ruby ui_objects += phoenix ruby
ui_objects += $(if $(call streq,$(platform),win),resource) ui_objects += $(if $(call streq,$(platform),windows),resource)
# platform # platform
ifeq ($(platform),x) ifeq ($(platform),windows)
ruby := video.glx video.xv video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x
else ifeq ($(platform),osx)
ruby := video.cgl
ruby += audio.openal
ruby += input.carbon
else ifeq ($(platform),win)
ruby := video.direct3d video.wgl video.directdraw video.gdi ruby := video.direct3d video.wgl video.directdraw video.gdi
ruby += audio.directsound audio.xaudio2 ruby += audio.directsound audio.xaudio2
ruby += input.rawinput input.directinput ruby += input.rawinput input.directinput
else ifeq ($(platform),macosx)
ruby := video.cgl
ruby += audio.openal
ruby += input.carbon
else ifeq ($(platform),linux)
ruby := video.glx video.xv video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x
else ifeq ($(platform),bsd)
ruby := video.glx
ruby += audio.openal audio.oss
ruby += input.x
endif endif
# phoenix # phoenix
@@ -65,9 +69,10 @@ endif
# targets # targets
build: $(objects) build: $(objects)
ifeq ($(platform),x) ifeq ($(platform),windows)
$(strip $(compiler) -o out/$(name) $(objects) $(link)) $(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink))
else ifeq ($(platform),osx) $(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
else ifeq ($(platform),macosx)
if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
mkdir out/$(name).app mkdir out/$(name).app
mkdir out/$(name).app/Contents mkdir out/$(name).app/Contents
@@ -76,16 +81,21 @@ else ifeq ($(platform),osx)
cp data/Info.plist out/$(name).app/Contents/Info.plist cp data/Info.plist out/$(name).app/Contents/Info.plist
sips -s format icns data/higan512.png --out out/$(name).app/Contents/Resources/higan.icns sips -s format icns data/higan512.png --out out/$(name).app/Contents/Resources/higan.icns
$(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link)) $(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link))
else ifeq ($(platform),win) else
$(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink)) $(strip $(compiler) -o out/$(name) $(objects) $(link))
$(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
endif endif
resource: resource:
sourcery $(ui)/resource/resource.bml $(ui)/resource/resource.cpp $(ui)/resource/resource.hpp sourcery $(ui)/resource/resource.bml $(ui)/resource/resource.cpp $(ui)/resource/resource.hpp
install: install:
ifeq ($(platform),x) ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
sudo mkdir -p /Library/Application\ Support/$(name)
sudo cp -R profile/* /Library/Application\ Support/$(name)
sudo cp data/cheats.bml /Library/Application\ Support/$(name)/cheats.bml
sudo chmod -R 777 /Library/Application\ Support/$(name)
else
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name) sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
sudo install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png sudo install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
@@ -94,14 +104,11 @@ ifeq ($(platform),x)
sudo cp -R profile/* /usr/share/$(name) sudo cp -R profile/* /usr/share/$(name)
sudo cp data/cheats.bml /usr/share/$(name)/cheats.bml sudo cp data/cheats.bml /usr/share/$(name)/cheats.bml
sudo chmod -R 777 /usr/share/$(name) sudo chmod -R 777 /usr/share/$(name)
else ifeq ($(platform),osx)
sudo mkdir -p /Library/Application\ Support/$(name)
sudo cp -R profile/* /Library/Application\ Support/$(name)
sudo cp data/cheats.bml /Library/Application\ Support/$(name)/cheats.bml
sudo chmod -R 777 /Library/Application\ Support/$(name)
endif endif
uninstall: uninstall:
ifeq ($(platform),x) ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
else
sudo rm $(DESTDIR)$(prefix)/bin/$(name) sudo rm $(DESTDIR)$(prefix)/bin/$(name)
endif endif

View File

@@ -28,7 +28,7 @@ Browser::Browser() {
}; };
homeButton.onActivate = [&] { homeButton.onActivate = [&] {
string libraryPath = string::read({configpath(), "higan/library.cfg"}).strip(); string libraryPath = string::read({configpath(), "higan/library.bml"}).strip().ltrim<1>("Path: ").transform("\\", "/");
if(libraryPath.empty()) libraryPath = {userpath(), "Emulation/"}; if(libraryPath.empty()) libraryPath = {userpath(), "Emulation/"};
if(libraryPath.endswith("/") == false) libraryPath.append("/"); if(libraryPath.endswith("/") == false) libraryPath.append("/");
setPath(libraryPath); setPath(libraryPath);

View File

@@ -12,6 +12,7 @@ void Presentation::synchronize() {
shaderNone.setChecked(); shaderNone.setChecked();
if(config->video.shader == "None") shaderNone.setChecked(); if(config->video.shader == "None") shaderNone.setChecked();
if(config->video.shader == "Blur") shaderBlur.setChecked(); if(config->video.shader == "Blur") shaderBlur.setChecked();
if(config->video.shader == "Emulation") shaderEmulation.setChecked();
for(auto& shader : shaderList) { for(auto& shader : shaderList) {
string name = notdir(config->video.shader.split<1>(".shader/")(0)); string name = notdir(config->video.shader.split<1>(".shader/")(0));
if(name == shader->text()) shader->setChecked(); if(name == shader->text()) shader->setChecked();
@@ -43,7 +44,7 @@ void Presentation::synchronize() {
} }
void Presentation::setSystemName(string name) { void Presentation::setSystemName(string name) {
if(active) active->menu.setText(name); if(active) active->menu.setText(systemName = name);
} }
Presentation::Presentation() { Presentation::Presentation() {
@@ -73,6 +74,7 @@ Presentation::Presentation() {
shaderMenu.setText("Shader"); shaderMenu.setText("Shader");
shaderNone.setText("None"); shaderNone.setText("None");
shaderBlur.setText("Blur"); shaderBlur.setText("Blur");
shaderEmulation.setText("Display Emulation");
synchronizeVideo.setText("Synchronize Video"); synchronizeVideo.setText("Synchronize Video");
synchronizeAudio.setText("Synchronize Audio"); synchronizeAudio.setText("Synchronize Audio");
muteAudio.setText("Mute Audio"); muteAudio.setText("Mute Audio");
@@ -96,8 +98,11 @@ Presentation::Presentation() {
videoMenu.append(centerVideo, scaleVideo, stretchVideo, *new Separator, aspectCorrection, maskOverscan); videoMenu.append(centerVideo, scaleVideo, stretchVideo, *new Separator, aspectCorrection, maskOverscan);
settingsMenu.append(shaderMenu); settingsMenu.append(shaderMenu);
shaderMenu.append(shaderNone, shaderBlur); shaderMenu.append(shaderNone, shaderBlur);
if(shaderList.size() > 0) shaderMenu.append(*new Separator); if(config->video.driver == "OpenGL") shaderMenu.append(shaderEmulation);
for(auto& shader : shaderList) shaderMenu.append(*shader); if(shaderList.size() > 0) {
shaderMenu.append(*new Separator);
for(auto& shader : shaderList) shaderMenu.append(*shader);
}
settingsMenu.append(*new Separator); settingsMenu.append(*new Separator);
settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio); settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio);
if(Intrinsics::platform() != Intrinsics::Platform::OSX) { if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
@@ -146,6 +151,7 @@ Presentation::Presentation() {
shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); }; shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); };
shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); }; shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); };
shaderEmulation.onActivate = [&] { config->video.shader = "Emulation"; utility->updateShader(); };
centerVideo.onActivate = [&] { config->video.scaleMode = 0; utility->resize(); }; centerVideo.onActivate = [&] { config->video.scaleMode = 0; utility->resize(); };
scaleVideo.onActivate = [&] { config->video.scaleMode = 1; utility->resize(); }; scaleVideo.onActivate = [&] { config->video.scaleMode = 1; utility->resize(); };
stretchVideo.onActivate = [&] { config->video.scaleMode = 2; utility->resize(); }; stretchVideo.onActivate = [&] { config->video.scaleMode = 2; utility->resize(); };
@@ -245,6 +251,7 @@ void Presentation::loadShaders() {
nall::group<RadioItem> group; nall::group<RadioItem> group;
group.append(shaderNone); group.append(shaderNone);
group.append(shaderBlur); group.append(shaderBlur);
group.append(shaderEmulation);
for(auto& shader : shaderList) group.append(*shader); for(auto& shader : shaderList) group.append(*shader);
RadioItem::group(group); RadioItem::group(group);
} }

View File

@@ -35,6 +35,7 @@ struct Presentation : Window {
Menu shaderMenu; Menu shaderMenu;
RadioItem shaderNone; RadioItem shaderNone;
RadioItem shaderBlur; RadioItem shaderBlur;
RadioItem shaderEmulation;
vector<RadioItem*> shaderList; vector<RadioItem*> shaderList;
CheckItem synchronizeVideo; CheckItem synchronizeVideo;
CheckItem synchronizeAudio; CheckItem synchronizeAudio;
@@ -56,6 +57,9 @@ struct Presentation : Window {
void loadShaders(); void loadShaders();
void bootstrap(); void bootstrap();
Presentation(); Presentation();
//internal:
string systemName;
}; };
extern Presentation* presentation; extern Presentation* presentation;

View File

@@ -110,6 +110,7 @@ void Utility::load() {
synchronizeDSP(); synchronizeDSP();
resize(); resize();
updateShader();
cheatEditor->synchronize(); cheatEditor->synchronize();
cheatEditor->refresh(); cheatEditor->refresh();
} }
@@ -198,14 +199,28 @@ void Utility::updateShader() {
if(config->video.shader == "None") { if(config->video.shader == "None") {
video.set(Video::Shader, (const char*)""); video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterNearest); video.set(Video::Filter, Video::FilterNearest);
return; } else if(config->video.shader == "Blur") {
}
if(config->video.shader == "Blur") {
video.set(Video::Shader, (const char*)""); video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear); video.set(Video::Filter, Video::FilterLinear);
return; return;
} else if(config->video.shader == "Emulation") {
if(program->active) {
string pathname = program->path("Video Shaders/");
pathname.append("Emulation/");
pathname.append(presentation->systemName, ".shader/");
if(directory::exists(pathname)) {
video.set(Video::Shader, (const char*)pathname);
} else {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
}
} else {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
}
} else {
video.set(Video::Shader, (const char*)config->video.shader);
} }
video.set(Video::Shader, (const char*)config->video.shader);
} }
void Utility::resize(bool resizeWindow) { void Utility::resize(bool resizeWindow) {