Update to v084r05 release.

(note: before the post announcing this release, there had been
a discussion of a performance optimisation that made the Super Scope
emulation a lot faster, but caused problems for the Justifier perpheral)

byuu says:

Spent a good two hours trying things to no avail.
I was trying to allow the CPU to run ahead, and sync on accesses to
$4016/4017/4201/4213, but that doesn't work because the controllers have
access to strobe IObit at will.
The codebase is really starting to get difficult to work with. I am
guessing because the days of massive development are long over, and the
code is starting to age.
Jonas' fix works 98% of the time, but there's still a few missed shots
here and there. So that's not going to work either.
So ... I give up. I've disabled the speed hack, so that it works 100% of
the time.
Did the same for the Super Scope: it may not have the same problem, but
I like consistency and don't feel like taking the chance.
This doesn't affect the mouse, since the mouse does not latch the
counters to indicate its X/Y position.
Speed hit is 92->82fps (accuracy profile), but only for Super Scope and
Justifier games.
But ... at least it works now. Slow and working is better than fast and
broken.

I appreciate the help in researching the issue, Jonas and krom.

Also pulled in phoenix/Makefile, which simplifies ui/Makefile.
Linux port defaults to GTK+ now. I can't get QGtkStyle to look good on
Debian.
This commit is contained in:
Tim Allen 2011-12-18 14:19:45 +11:00
parent ea95eaca3c
commit 6227974bf6
23 changed files with 241 additions and 118 deletions

View File

@ -41,6 +41,9 @@ ifeq ($(compiler),)
endif endif
endif endif
c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
ifeq ($(prefix),) ifeq ($(prefix),)
prefix := /usr/local prefix := /usr/local
endif endif

View File

@ -9,8 +9,9 @@ struct context {
unsigned height; unsigned height;
unsigned count; unsigned count;
bool endian; bool endian; //0 = lsb, 1 = msb
unsigned depth; bool order; //0 = linear, 1 = planar
unsigned depth; //1 - 24bpp
unsigned blockWidth; unsigned blockWidth;
unsigned blockHeight; unsigned blockHeight;
@ -51,21 +52,61 @@ struct context {
return result; return result;
} }
inline void eval(array<unsigned> &buffer, const string &expression) { inline void eval(array<unsigned> &buffer, const string &expression_) {
string expression = expression_;
bool function = false;
for(auto &c : expression) {
if(c == '(') function = true;
if(c == ')') function = false;
if(c == ',' && function == true) c = ';';
}
lstring list = expression.split(","); lstring list = expression.split(",");
for(auto &item : list) { for(auto &item : list) {
item.trim(); item.trim();
if(item.wildcard("f(?*) *")) { if(item.wildcard("f(?*) ?*")) {
lstring part = item.split<1>(" "); item.ltrim<1>("f(");
part[0].trim("f(", ")"); lstring part = item.split<1>(") ");
unsigned length = decimal(part[0].trim()); lstring args = part[0].split<3>(";");
for(auto &item : args) item.trim();
unsigned length = eval(args(0, "0"));
unsigned offset = eval(args(1, "0"));
unsigned stride = eval(args(2, "0"));
if(args.size() < 2) offset = buffer.size();
if(args.size() < 3) stride = 1;
for(unsigned n = 0; n < length; n++) { for(unsigned n = 0; n < length; n++) {
string fn = part[1]; string fn = part[1];
fn.replace("n", decimal(n)); fn.replace("n", decimal(n));
fn.replace("o", decimal(offset));
fn.replace("p", decimal(buffer.size())); fn.replace("p", decimal(buffer.size()));
buffer.append(eval(fn)); buffer.resize(offset + 1);
buffer[offset] = eval(fn);
offset += stride;
} }
} else if(item != "") { } else if(item.wildcard("base64*")) {
unsigned offset = 0;
item.ltrim<1>("base64");
if(item.wildcard("(?*) *")) {
item.ltrim<1>("(");
lstring part = item.split<1>(") ");
offset = eval(part[0]);
item = part(1, "");
}
item.trim();
for(auto &c : item) {
if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0);
if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26);
if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52);
if(c == '-') buffer.append(offset + 62);
if(c == '_') buffer.append(offset + 63);
}
} else if(item.wildcard("file *")) {
item.ltrim<1>("file ");
item.trim();
//...
} else if(item.empty() == false) {
buffer.append(eval(item)); buffer.append(eval(item));
} }
} }
@ -87,6 +128,7 @@ struct context {
if(part[0] == "count") count = eval(part[1]); if(part[0] == "count") count = eval(part[1]);
if(part[0] == "endian") endian = eval(part[1]); if(part[0] == "endian") endian = eval(part[1]);
if(part[0] == "order") order = eval(part[1]);
if(part[0] == "depth") depth = eval(part[1]); if(part[0] == "depth") depth = eval(part[1]);
if(part[0] == "blockWidth") blockWidth = eval(part[1]); if(part[0] == "blockWidth") blockWidth = eval(part[1]);
@ -144,6 +186,7 @@ struct context {
count = 0; count = 0;
endian = 1; endian = 1;
order = 0;
depth = 1; depth = 1;
blockWidth = 1; blockWidth = 1;

View File

@ -6,13 +6,15 @@ namespace mosaic {
struct parser { struct parser {
image canvas; image canvas;
inline void importData(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) { //export from bitstream to canvas
inline void load(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
canvas.allocate(width, height); canvas.allocate(width, height);
canvas.clear(ctx.paddingColor); canvas.clear(ctx.paddingColor);
parse(1, stream, offset, ctx, width, height); parse(1, stream, offset, ctx, width, height);
} }
inline bool exportData(bitstream &stream, uint64_t offset, context &ctx) { //import from canvas to bitstream
inline bool save(bitstream &stream, uint64_t offset, context &ctx) {
if(stream.readonly) return false; if(stream.readonly) return false;
parse(0, stream, offset, ctx, canvas.width, canvas.height); parse(0, stream, offset, ctx, canvas.width, canvas.height);
return true; return true;
@ -36,39 +38,45 @@ private:
buffer[addr] = data; buffer[addr] = data;
} }
inline void parse(bool import, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) { inline void parse(bool load, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
stream.endian = ctx.endian; stream.endian = ctx.endian;
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth); unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight); unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
unsigned objectOffset = 0; unsigned objectOffset = 0;
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) { for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) { for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
if(objectOffset++ >= ctx.count && ctx.count > 0) break; if(objectOffset >= ctx.count && ctx.count > 0) break;
unsigned objectIX = objectX * ctx.objectWidth(); unsigned objectIX = objectX * ctx.objectWidth();
unsigned objectIY = objectY * ctx.objectHeight(); unsigned objectIY = objectY * ctx.objectHeight();
objectOffset++;
unsigned mosaicOffset = 0; unsigned mosaicOffset = 0;
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) { for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) { for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
unsigned mosaicData = ctx.mosaic(mosaicOffset++, 0); unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth); unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight); unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
mosaicOffset++;
unsigned tileOffset = 0; unsigned tileOffset = 0;
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) { for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) { for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
unsigned tileData = ctx.tile(tileOffset++, 0); unsigned tileData = ctx.tile(tileOffset, tileOffset);
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth; unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight; unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
tileOffset++;
unsigned blockOffset = 0; unsigned blockOffset = 0;
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) { for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) { for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
if(import) { if(load) {
unsigned palette = 0; unsigned palette = 0;
for(unsigned n = 0; n < ctx.depth; n++) { for(unsigned n = 0; n < ctx.depth; n++) {
palette |= stream.read(offset + ctx.block(blockOffset++, 0)) << n; unsigned index = blockOffset++;
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
palette |= stream.read(offset + ctx.block(index, index)) << n;
} }
write( write(
@ -76,14 +84,16 @@ private:
objectIY + mosaicIY + tileIY + blockY, objectIY + mosaicIY + tileIY + blockY,
ctx.palette(palette, palette) ctx.palette(palette, palette)
); );
} else { } else /* save */ {
uint32_t palette = read( uint32_t palette = read(
objectIX + mosaicIX + tileIX + blockX, objectIX + mosaicIX + tileIX + blockX,
objectIY + mosaicIY + tileIY + blockY objectIY + mosaicIY + tileIY + blockY
); );
for(unsigned n = 0; n < ctx.depth; n++) { for(unsigned n = 0; n < ctx.depth; n++) {
stream.write(offset + ctx.block(blockOffset++, 0), palette & 1); unsigned index = blockOffset++;
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
stream.write(offset + ctx.block(index, index), palette & 1);
palette >>= 1; palette >>= 1;
} }
} }

21
bsnes/phoenix/Makefile Executable file
View File

@ -0,0 +1,21 @@
ifeq ($(platform),x)
ifeq ($(phoenix),)
phoenix := gtk
endif
ifeq ($(phoenix),gtk)
phoenixflags := -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenixlink := `pkg-config --libs gtk+-2.0`
endif
ifeq ($(phoenix),qt)
phoenixflags := -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink := `pkg-config --libs QtCore QtGui`
endif
else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32
else
phoenixflags := -DPHOENIX_REFERENCE
phoenixlink :=
endif

View File

@ -19,7 +19,15 @@ Window Window::None;
//Geometry //Geometry
//======== //========
string Geometry::text() { Position Geometry::position() const {
return { x, y };
}
Size Geometry::size() const {
return { width, height };
}
string Geometry::text() const {
return { x, ",", y, ",", width, ",", height }; return { x, ",", y, ",", width, ",", height };
} }

View File

@ -47,15 +47,6 @@ struct Color {
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {} inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
}; };
struct Geometry {
signed x, y;
unsigned width, height;
nall::string text();
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
Geometry(const nall::string &text);
};
struct Position { struct Position {
signed x, y; signed x, y;
inline Position() : x(0), y(0) {} inline Position() : x(0), y(0) {}
@ -68,6 +59,17 @@ struct Size {
inline Size(unsigned width, unsigned height) : width(width), height(height) {} inline Size(unsigned width, unsigned height) : width(width), height(height) {}
}; };
struct Geometry {
signed x, y;
unsigned width, height;
Position position() const;
Size size() const;
nall::string text() const;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
Geometry(const nall::string &text);
};
struct Font { struct Font {
nall::string description; nall::string description;
Geometry geometry(const nall::string &text); Geometry geometry(const nall::string &text);

View File

@ -165,13 +165,16 @@ void pOS::initialize() {
char **argvp = argv; char **argvp = argv;
gtk_init(&argc, &argvp); gtk_init(&argc, &argvp);
gtk_rc_parse_string( gtk_rc_parse_string(R"(
"style \"phoenix-gtk\"\n" style "phoenix-gtk"
"{\n" {
" GtkComboBox::appears-as-list = 1\n" GtkWindow::resize-grip-width = 0
" GtkTreeView::vertical-separator = 0\n" GtkWindow::resize-grip-height = 0
"}\n" GtkTreeView::vertical-separator = 0
//"class \"GtkComboBox\" style \"phoenix-gtk\"\n" GtkComboBox::appears-as-list = 1
"class \"GtkTreeView\" style \"phoenix-gtk\"\n" }
); class "GtkWindow" style "phoenix-gtk"
class "GtkTreeView" style "phoenix-gtk"
# class "GtkComboBox" style "phoenix-gtk"
)");
} }

View File

@ -15,7 +15,7 @@ unsigned pHorizontalScrollBar::position() {
void pHorizontalScrollBar::setLength(unsigned length) { void pHorizontalScrollBar::setLength(unsigned length) {
locked = true; locked = true;
length += length == 0; length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
locked = false; locked = false;
} }

View File

@ -14,7 +14,7 @@ unsigned pHorizontalSlider::position() {
void pHorizontalSlider::setLength(unsigned length) { void pHorizontalSlider::setLength(unsigned length) {
length += length == 0; length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
} }

View File

@ -15,7 +15,7 @@ unsigned pVerticalScrollBar::position() {
void pVerticalScrollBar::setLength(unsigned length) { void pVerticalScrollBar::setLength(unsigned length) {
locked = true; locked = true;
length += length == 0; length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
locked = false; locked = false;
} }

View File

@ -14,7 +14,7 @@ unsigned pVerticalSlider::position() {
void pVerticalSlider::setLength(unsigned length) { void pVerticalSlider::setLength(unsigned length) {
length += length == 0; length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
} }

View File

@ -6,6 +6,7 @@ static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) {
} }
static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) { static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) {
if(window->state.backgroundColorOverride == false) return false;
cairo_t *context = gdk_cairo_create(widget->window); cairo_t *context = gdk_cairo_create(widget->window);
Color color = window->backgroundColor(); Color color = window->backgroundColor();
@ -241,6 +242,10 @@ void pWindow::constructor() {
} }
gtk_window_set_resizable(GTK_WINDOW(widget), true); gtk_window_set_resizable(GTK_WINDOW(widget), true);
#if GTK_MAJOR_VERSION >= 3
gtk_window_set_has_resize_grip(GTK_WINDOW(widget), false);
#endif
gtk_widget_set_app_paintable(widget, true); gtk_widget_set_app_paintable(widget, true);
gtk_widget_add_events(widget, GDK_CONFIGURE); gtk_widget_add_events(widget, GDK_CONFIGURE);

View File

@ -1,6 +1,7 @@
#ifndef PHOENIX_HPP #ifndef PHOENIX_HPP
#define PHOENIX_HPP #define PHOENIX_HPP
#include <nall/platform.hpp>
#include <nall/array.hpp> #include <nall/array.hpp>
#include <nall/config.hpp> #include <nall/config.hpp>
#include <nall/function.hpp> #include <nall/function.hpp>

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Sun Dec 11 12:26:40 2011 ** Created: Tue Dec 13 07:23:09 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -4,7 +4,8 @@ void pCanvas::setSize(const Size &size) {
} }
void pCanvas::update() { void pCanvas::update() {
memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); uint32_t *dp = (uint32_t*)qtImage->bits(), *sp = (uint32_t*)canvas.state.data;
for(unsigned n = 0; n < canvas.state.width * canvas.state.height; n++) *dp++ = 0xff000000 | *sp++;
qtCanvas->update(); qtCanvas->update();
} }

View File

@ -31,7 +31,7 @@
#include "widget/vertical-slider.cpp" #include "widget/vertical-slider.cpp"
#include "widget/viewport.cpp" #include "widget/viewport.cpp"
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); static bool OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
static void OS_processDialogMessage(MSG&); static void OS_processDialogMessage(MSG&);
static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM);
@ -150,7 +150,10 @@ void pOS::processEvents() {
void OS_processDialogMessage(MSG &msg) { void OS_processDialogMessage(MSG &msg) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) { if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); if(OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) {
DispatchMessage(&msg);
return;
}
} }
if(!IsDialogMessage(GetForegroundWindow(), &msg)) { if(!IsDialogMessage(GetForegroundWindow(), &msg)) {
@ -217,14 +220,14 @@ void pOS::initialize() {
RegisterClass(&wc); RegisterClass(&wc);
} }
static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static bool OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(msg == WM_KEYDOWN) { if(msg == WM_KEYDOWN) {
GUITHREADINFO info; GUITHREADINFO info;
memset(&info, 0, sizeof(GUITHREADINFO)); memset(&info, 0, sizeof(GUITHREADINFO));
info.cbSize = sizeof(GUITHREADINFO); info.cbSize = sizeof(GUITHREADINFO);
GetGUIThreadInfo(GetCurrentThreadId(), &info); GetGUIThreadInfo(GetCurrentThreadId(), &info);
Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
if(object == 0) return; if(object == nullptr) return false;
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) {
@ -235,8 +238,48 @@ static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(wparam == VK_RETURN) { if(wparam == VK_RETURN) {
if(lineEdit.onActivate) lineEdit.onActivate(); if(lineEdit.onActivate) lineEdit.onActivate();
} }
} else if(dynamic_cast<TextEdit*>(object)) {
TextEdit &textEdit = (TextEdit&)*object;
if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) {
//Ctrl+A = select all text
//note: this is not a standard accelerator on Windows
Edit_SetSel(textEdit.p.hwnd, 0, ~0);
return true;
} else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) {
//Ctrl+V = paste text
//note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings
//this is necessary as the EDIT control only supports Windows line-endings
OpenClipboard(hwnd);
HANDLE handle = GetClipboardData(CF_UNICODETEXT);
if(handle) {
wchar_t *text = (wchar_t*)GlobalLock(handle);
if(text) {
string data = (const char*)utf8_t(text);
data.replace("\r\n", "\n");
data.replace("\r", "\n");
data.replace("\n", "\r\n");
GlobalUnlock(handle);
utf16_t output(data);
HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t));
if(resource) {
wchar_t *write = (wchar_t*)GlobalLock(resource);
if(write) {
wcscpy(write, output);
GlobalUnlock(write);
if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) {
GlobalFree(resource);
}
}
}
}
}
CloseClipboard();
return false;
}
} }
} }
return false;
} }
static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {

View File

@ -18,9 +18,9 @@ rubylink += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid) rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
ifeq ($(platform),x) ifeq ($(platform),x)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal) rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL) rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win) else ifeq ($(platform),win)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32) rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
endif endif

View File

@ -5,7 +5,7 @@ void Justifier::enter() {
while(true) { while(true) {
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
signed x = (active == 0 ? x1 : x2), y = (active == 0 ? y1 : y2); signed x = (active == 0 ? player1.x : player2.x), y = (active == 0 ? player1.y : player2.y);
bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225));
if(offscreen == false) { if(offscreen == false) {
@ -20,23 +20,19 @@ void Justifier::enter() {
if(next < prev) { if(next < prev) {
int nx1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X); int nx1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X);
int ny1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y); int ny1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y);
nx1 += x1; nx1 += player1.x;
ny1 += y1; ny1 += player1.y;
x1 = max(-16, min(256 + 16, nx1)); player1.x = max(-16, min(256 + 16, nx1));
y1 = max(-16, min(240 + 16, ny1)); player1.y = max(-16, min(240 + 16, ny1));
}
if(chained == true) { if(next < prev && chained) {
int nx2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X); int nx2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X);
int ny2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y); int ny2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y);
nx2 += x2; nx2 += player2.x;
ny2 += y2; ny2 += player2.y;
x2 = max(-16, min(256 + 16, nx2)); player2.x = max(-16, min(256 + 16, nx2));
y2 = max(-16, min(240 + 16, ny2)); player2.y = max(-16, min(240 + 16, ny2));
}
} else {
//sleep until PPU counters are close to latch position
unsigned diff = abs((signed)y - cpu.vcounter());
if(diff >= 2) step((diff - 2) * 1364);
} }
prev = next; prev = next;
@ -48,12 +44,13 @@ uint2 Justifier::data() {
if(counter >= 32) return 1; if(counter >= 32) return 1;
if(counter == 0) { if(counter == 0) {
trigger1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger); player1.trigger = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger);
start1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start); player1.start = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start);
if(chained) { }
trigger2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
start2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start); if(counter == 0 && chained) {
} player2.trigger = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger);
player2.start = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start);
} }
switch(counter++) { switch(counter++) {
@ -84,10 +81,10 @@ uint2 Justifier::data() {
case 22: return 0; case 22: return 0;
case 23: return 1; case 23: return 1;
case 24: return trigger1; case 24: return player1.trigger;
case 25: return trigger2; case 25: return player2.trigger;
case 26: return start1; case 26: return player1.start;
case 27: return start2; case 27: return player2.start;
case 28: return active; case 28: return active;
case 29: return 0; case 29: return 0;
@ -109,23 +106,23 @@ Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chaine
counter = 0; counter = 0;
active = 0; active = 0;
player1.x = 256 / 2;
player1.y = 240 / 2;
player1.trigger = false;
player2.start = false;
player2.x = 256 / 2;
player2.y = 240 / 2;
player2.trigger = false;
player2.start = false;
if(chained == false) { if(chained == false) {
x1 = 256 / 2; player2.x = -1;
y1 = 240 / 2; player2.y = -1;
x2 = -1;
y2 = -1;
} else { } else {
x1 = 256 / 2 - 16; player1.x -= 16;
y1 = 240 / 2; player2.x += 16;
x2 = 256 / 2 + 16;
y2 = 240 / 2;
} }
trigger1 = false;
trigger2 = false;
start1 = false;
start2 = false;
} }
#endif #endif

View File

@ -10,8 +10,8 @@ struct Justifier : Controller {
unsigned counter; unsigned counter;
bool active; bool active;
signed x1, x2; struct Player {
signed y1, y2; signed x, y;
bool trigger1, trigger2; bool trigger, start;
bool start1, start2; } player1, player2;
}; };

View File

@ -35,10 +35,6 @@ void SuperScope::enter() {
x = max(-16, min(256 + 16, nx)); x = max(-16, min(256 + 16, nx));
y = max(-16, min(240 + 16, ny)); y = max(-16, min(240 + 16, ny));
offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225));
} else {
//sleep until PPU counters are close to latch position
unsigned diff = abs((signed)y - cpu.vcounter());
if(diff >= 2) step((diff - 2) * 1364);
} }
prev = next; prev = next;

View File

@ -107,9 +107,9 @@ void Video::update() {
case Input::Device::Justifiers: case Input::Device::Justifiers:
if(dynamic_cast<Justifier*>(input.port2)) { if(dynamic_cast<Justifier*>(input.port2)) {
Justifier &device = (Justifier&)*input.port2; Justifier &device = (Justifier&)*input.port2;
draw_cursor(0x001f, device.x1, device.y1); draw_cursor(0x001f, device.player1.x, device.player1.y);
if(device.chained == false) break; if(device.chained == false) break;
draw_cursor(0x02e0, device.x2, device.y2); draw_cursor(0x02e0, device.player2.x, device.player2.y);
} }
break; break;
} }

View File

@ -10,33 +10,23 @@ ui_objects += $(if $(call streq,$(platform),win),resource)
# platform # platform
ifeq ($(platform),x) ifeq ($(platform),x)
ifeq ($(phoenix),gtk)
phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`)
link += `pkg-config --libs gtk+-2.0`
else
phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`)
link += `pkg-config --libs QtCore QtGui`
endif
ruby := video.glx video.xv video.sdl ruby := video.glx video.xv video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x ruby += input.sdl input.x
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
phoenix_compile = $(call compile,-DPHOENIX_QT)
link +=
ruby := ruby :=
ruby += audio.openal ruby += audio.openal
ruby += input.carbon ruby += input.carbon
else ifeq ($(platform),win) else ifeq ($(platform),win)
phoenix_compile = $(call compile,-DPHOENIX_WINDOWS)
link +=
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
endif endif
# phoenix
include phoenix/Makefile
link += $(phoenixlink)
# ruby # ruby
include ruby/Makefile include ruby/Makefile
link += $(rubylink) link += $(rubylink)
@ -59,7 +49,7 @@ obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubyflags)) $(call compile,$(rubyflags))
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*) obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
$(phoenix_compile) $(call compile,$(phoenixflags))
obj/resource.o: $(ui)/resource.rc obj/resource.o: $(ui)/resource.rc
# windres --target=pe-i386 $(ui)/resource.rc obj/resource.o # windres --target=pe-i386 $(ui)/resource.rc obj/resource.o

View File

@ -27,7 +27,7 @@ void Application::run() {
} }
Application::Application(int argc, char **argv) { Application::Application(int argc, char **argv) {
title = "bsnes v084.04"; title = "bsnes v084.05";
application = this; application = this;
quit = false; quit = false;