Update to v072r01 release.

byuu says:

- added pause shortcut ('P' key, as pause/break is too finicky)
- pause and auto-pause show on status bar
- added a debugger skeleton, very very primitive and completely unusable
  - don't try it yet
- added software filter support

Also included is the new snesfilter library. It has all of the filters
the old one had, as well as scanline filters since that's not in my GUI
anymore
If you want scanlines and other software filters, then you can either
make your own hybrid two-in-one software filter, or make a pixel shader
(I don't have one of those yet.)
This commit is contained in:
Tim Allen 2010-10-26 23:01:41 +11:00
parent d0ef8e7488
commit 5ae0c80ee8
99 changed files with 2209 additions and 2428 deletions

View File

@ -1,6 +1,6 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
profile := accuracy profile := performance
ui := ui-phoenix ui := ui-phoenix
# compiler # compiler

View File

@ -19,6 +19,7 @@ namespace nall {
struct library { struct library {
bool opened() const { return handle; } bool opened() const { return handle; }
bool open(const char*, const char* = ""); bool open(const char*, const char* = "");
bool open_absolute(const char*);
void* sym(const char*); void* sym(const char*);
void close(); void close();
@ -40,6 +41,12 @@ namespace nall {
return handle; return handle;
} }
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) { inline void* library::sym(const char *name) {
if(!handle) return 0; if(!handle) return 0;
return dlsym((void*)handle, name); return dlsym((void*)handle, name);
@ -58,6 +65,12 @@ namespace nall {
return handle; return handle;
} }
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) { inline void* library::sym(const char *name) {
if(!handle) return 0; if(!handle) return 0;
return dlsym((void*)handle, name); return dlsym((void*)handle, name);
@ -76,6 +89,12 @@ namespace nall {
return handle; return handle;
} }
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
return handle;
}
inline void* library::sym(const char *name) { inline void* library::sym(const char *name) {
if(!handle) return 0; if(!handle) return 0;
return (void*)GetProcAddress((HMODULE)handle, name); return (void*)GetProcAddress((HMODULE)handle, name);

View File

@ -558,6 +558,11 @@ void snes_information::read_header(const uint8_t *data, unsigned size) {
} }
} }
if(size < 32768) {
type = TypeUnknown;
return;
}
const unsigned index = find_header(data, size); const unsigned index = find_header(data, size);
const uint8_t mapperid = data[index + Mapper]; const uint8_t mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType]; const uint8_t rom_type = data[index + RomType];

View File

@ -27,6 +27,7 @@ namespace phoenix {
#include "checkbox.cpp" #include "checkbox.cpp"
#include "combobox.cpp" #include "combobox.cpp"
#include "editbox.cpp" #include "editbox.cpp"
#include "hexeditor.cpp"
#include "horizontalslider.cpp" #include "horizontalslider.cpp"
#include "label.cpp" #include "label.cpp"
#include "listbox.cpp" #include "listbox.cpp"

View File

@ -159,6 +159,24 @@ struct EditBox : Widget {
void setText(const nall::string &text); void setText(const nall::string &text);
}; };
struct HexEditor : Widget {
nall::function<uint8_t (unsigned)> onRead;
nall::function<void (unsigned, uint8_t)> onWrite;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setSize(unsigned size);
void setOffset(unsigned offset);
void setColumns(unsigned columns);
void setRows(unsigned rows);
void update();
HexEditor();
//private:
struct Data;
Data *hexEditor;
bool keyPress(unsigned scancode);
unsigned cursorPosition();
void setCursorPosition(unsigned position);
};
struct HorizontalSlider : Widget { struct HorizontalSlider : Widget {
nall::function<void ()> onChange; nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length); void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);

213
bsnes/phoenix/gtk/hexeditor.cpp Executable file
View File

@ -0,0 +1,213 @@
static bool HexEditor_keyPress(GtkWidget *widget, GdkEventKey *event, HexEditor *self) {
return self->keyPress(event->keyval);
}
void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_scrolled_window_new(0, 0);
widget->parent = &parent;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
gtk_widget_set_size_request(object->widget, width, height);
object->subWidget = gtk_text_view_new();
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), GTK_WRAP_NONE);
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(object->subWidget));
hexEditor->cursor = gtk_text_buffer_get_mark(object->textBuffer, "insert");
gtk_text_view_set_editable(GTK_TEXT_VIEW(object->subWidget), false);
g_signal_connect(G_OBJECT(object->subWidget), "key-press-event", G_CALLBACK(HexEditor_keyPress), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->subWidget);
gtk_widget_show(object->widget);
}
void HexEditor::setSize(unsigned size) {
hexEditor->size = size;
}
void HexEditor::setOffset(unsigned offset) {
hexEditor->offset = offset;
}
void HexEditor::setColumns(unsigned columns) {
hexEditor->columns = columns;
}
void HexEditor::setRows(unsigned rows) {
hexEditor->rows = rows;
}
void HexEditor::update() {
if(!onRead) {
gtk_text_buffer_set_text(object->textBuffer, "", -1);
return;
}
unsigned position = cursorPosition();
string output;
unsigned offset = hexEditor->offset;
for(unsigned row = 0; row < hexEditor->rows; row++) {
output.append(strhex<8>(offset));
output.append(" ");
string hexdata;
string ansidata = " ";
for(unsigned column = 0; column < hexEditor->columns; column++) {
if(offset < hexEditor->size) {
uint8_t data = onRead(offset++);
hexdata.append(strhex<2>(data));
hexdata.append(" ");
char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 };
ansidata.append(buffer);
} else {
hexdata.append(" ");
ansidata.append(" ");
}
}
output.append(hexdata);
output.append(ansidata);
if(offset >= hexEditor->size) break;
if(row != hexEditor->rows - 1) output.append("\n");
}
gtk_text_buffer_set_text(object->textBuffer, output, -1);
if(position == 0) position = 10; //start at first position where hex values can be entered
setCursorPosition(position);
}
HexEditor::HexEditor() {
hexEditor = new HexEditor::Data;
}
//internal
bool HexEditor::keyPress(unsigned scancode) {
if(!onRead && !onWrite) return false;
unsigned position = cursorPosition();
unsigned lineWidth = 10 + (hexEditor->columns * 3) + 1 + (hexEditor->columns) + 1;
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
if(scancode == GDK_Home) {
setCursorPosition(cursorY * lineWidth + 10);
return true;
}
if(scancode == GDK_End) {
setCursorPosition(cursorY * lineWidth + 10 + (hexEditor->columns * 3 - 1));
return true;
}
if(scancode == GDK_Up) {
if(cursorY != 0) return false;
signed newOffset = hexEditor->offset - hexEditor->columns;
if(newOffset >= 0) {
setOffset(newOffset);
update();
}
return true;
}
if(scancode == GDK_Down) {
if(cursorY != hexEditor->rows - 1) return false;
signed newOffset = hexEditor->offset + hexEditor->columns;
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
setOffset(newOffset);
update();
}
return true;
}
if(scancode == GDK_Page_Up) {
signed newOffset = hexEditor->offset - hexEditor->columns * hexEditor->rows;
if(newOffset >= 0) {
setOffset(newOffset);
update();
} else {
setOffset(0);
update();
}
return true;
}
if(scancode == GDK_Page_Down) {
signed newOffset = hexEditor->offset + hexEditor->columns * hexEditor->rows;
for(unsigned n = 0; n < hexEditor->rows; n++) {
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
setOffset(newOffset);
update();
break;
}
newOffset -= hexEditor->columns;
}
return true;
}
//convert scancode to hex nibble
if(scancode >= '0' && scancode <= '9') scancode = scancode - '0';
else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10;
else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10;
else return false; //not a valid hex value
if(cursorX >= 10) {
//not on an offset
cursorX -= 10;
if((cursorX % 3) != 2) {
//not on a space
bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low
cursorX /= 3;
if(cursorX < hexEditor->columns) {
//not in ANSI region
unsigned offset = hexEditor->offset + (cursorY * hexEditor->columns + cursorX);
if(offset >= hexEditor->size) return false; //do not edit past end of file
uint8_t data = onRead(offset);
//write modified value
if(cursorNibble == 1) {
data = (data & 0xf0) | (scancode << 0);
} else {
data = (data & 0x0f) | (scancode << 4);
}
onWrite(offset, data);
//auto-advance cursor to next nibble/byte
position++;
if(cursorNibble && cursorX != hexEditor->columns - 1) position++;
setCursorPosition(position);
//refresh output to reflect modified data
update();
}
}
}
return false;
}
unsigned HexEditor::cursorPosition() {
GtkTextIter iter;
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
return gtk_text_iter_get_offset(&iter);
}
void HexEditor::setCursorPosition(unsigned position) {
GtkTextIter iter;
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
//GTK+ will throw a hundred errors on the terminal
//if you set an iterator past the end of the text buffer
GtkTextIter endIter;
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
unsigned endPosition = gtk_text_iter_get_offset(&iter);
gtk_text_iter_set_offset(&iter, min(position, endPosition));
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
}

View File

@ -35,6 +35,14 @@ struct Canvas::Data {
unsigned pitch; unsigned pitch;
}; };
struct HexEditor::Data {
GtkTextMark *cursor;
unsigned size;
unsigned offset;
unsigned columns;
unsigned rows;
};
struct ListBox::Data { struct ListBox::Data {
GtkListStore *store; GtkListStore *store;
struct GtkColumn { struct GtkColumn {

View File

@ -1,7 +1,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "072"; static const char Version[] = "072.01";
static const unsigned SerializerVersion = 14; static const unsigned SerializerVersion = 14;
} }
} }

View File

@ -1,4 +1,4 @@
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge ui-debugger
ui_objects += ruby phoenix ui_objects += ruby phoenix
ui_objects += $(if $(call streq,$(platform),win),resource) ui_objects += $(if $(call streq,$(platform),win),resource)
@ -64,6 +64,7 @@ obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(c
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*); $(phoenix_compile) obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*); $(phoenix_compile)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*); $(phoenix_compile) obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*); $(phoenix_compile)
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*); $(phoenix_compile) obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*); $(phoenix_compile)
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*); $(phoenix_compile)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*) obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubydef) $(rubyflags)) $(call compile,$(rubydef) $(rubyflags))

View File

@ -29,15 +29,21 @@ struct TopLevelWindow : Window {
#include "utility/utility.hpp" #include "utility/utility.hpp"
#include "cartridge/cartridge.hpp" #include "cartridge/cartridge.hpp"
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
#endif
struct Application { struct Application {
Font proportionalFont; Font proportionalFont;
Font proportionalFontBold; Font proportionalFontBold;
Font monospaceFont; Font monospaceFont;
bool pause;
bool quit; bool quit;
void main(int argc, char **argv); void main(int argc, char **argv);
void addWindow(TopLevelWindow *window, const string &name, const string &position); void addWindow(TopLevelWindow *window, const string &name, const string &position);
Application();
private: private:
array<TopLevelWindow*> windows; array<TopLevelWindow*> windows;

View File

@ -18,6 +18,7 @@ void Configuration::create() {
attach(video.driver = "", "video.driver"); attach(video.driver = "", "video.driver");
attach(video.synchronize = false, "video.synchronize"); attach(video.synchronize = false, "video.synchronize");
attach(video.smooth = true, "video.smooth"); attach(video.smooth = true, "video.smooth");
attach(video.filter = "", "video.filter");
attach(video.shader = "", "video.shader"); attach(video.shader = "", "video.shader");
attach(video.region = 0, "video.region"); attach(video.region = 0, "video.region");
attach(video.scale = 2, "video.scale"); attach(video.scale = 2, "video.scale");

View File

@ -12,6 +12,7 @@ struct Configuration : public configuration {
string driver; string driver;
bool synchronize; bool synchronize;
bool smooth; bool smooth;
string filter;
string shader; string shader;
bool region; bool region;
unsigned scale; unsigned scale;

View File

@ -0,0 +1,30 @@
Console console;
void Console::create() {
Window::create(0, 0, 256, 256, "Console");
application.addWindow(this, "Debugger.Console", "192,192");
unsigned x = 5, y = 5;
output.create(*this, x, y, 580, 328); x += 580 + 5;
output.setFont(application.monospaceFont);
output.setEditable(false);
traceToConsole.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to console"); y += Style::CheckBoxHeight + 5;
traceToConsole.setChecked(true);
traceToDisk.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace to disk"); y += Style::CheckBoxHeight + 5;
traceToDisk.setEnabled(false);
traceCPU.create(*this, x, y, 120, Style::CheckBoxHeight, "Trace S-CPU"); y += Style::CheckBoxHeight + 5;
traceCPU.setChecked(true);
setGeometry(0, 0, 775, 338);
}
void Console::eventTraceCPU() {
if(traceCPU.checked() == false) return;
if(traceToConsole.checked() == false) return;
char text[256];
SNES::cpu.disassemble_opcode(text, SNES::cpu.regs.pc);
buffer.append(string(buffer == "" ? "" : "\n", text));
output.setText(buffer);
}

View File

@ -0,0 +1,14 @@
struct Console : TopLevelWindow {
EditBox output;
CheckBox traceToConsole;
CheckBox traceToDisk;
CheckBox traceCPU;
string buffer;
void create();
void eventTraceCPU();
};
extern Console console;

View File

@ -0,0 +1,44 @@
CPUdebugger cpuDebugger;
void CPUdebugger::create() {
Window::create(0, 0, 256, 256, "CPU Debugger");
application.addWindow(this, "Debugger.CPUdebugger", "192,192");
unsigned x = 5, y = 5;
output.create(*this, x, y, 400, 200); x += 400 + 5;
output.setFont(application.monospaceFont);
output.setEditable(false);
stepInto.create(*this, x, y, 80, Style::ButtonHeight, "Step Into");
setGeometry(0, 0, 490, 205);
stepInto.onTick = []() {
SNES::debugger.step_cpu = true;
debugger.debugMode = Debugger::DebugMode::StepIntoCPU;
};
}
void CPUdebugger::eventStepInto() {
SNES::debugger.step_cpu = false;
char text[256];
SNES::cpu.disassemble_opcode(text, SNES::cpu.regs.pc);
text[21] = 0;
output.setText({
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
"> ", text, "\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ..."
});
}

View File

@ -0,0 +1,9 @@
struct CPUdebugger : TopLevelWindow {
EditBox output;
Button stepInto;
void create();
void eventStepInto();
};
extern CPUdebugger cpuDebugger;

View File

@ -0,0 +1,69 @@
#include "../base.hpp"
#if defined(DEBUGGER)
#include "console.cpp"
#include "cpu/debugger.cpp"
Debugger debugger;
void Debugger::create() {
console.create();
cpuDebugger.create();
Window::create(0, 0, 256, 256, "Debugger");
application.addWindow(this, "Debugger", "160,160");
unsigned x = 5, y = 5;
enableDebugger.create(*this, x, y, 390, Style::CheckBoxHeight, "Enable debugger"); y += Style::CheckBoxHeight + 5;
showMemoryEditor.create(*this, x, y, 390, Style::CheckBoxHeight, "Memory editor"); y += Style::CheckBoxHeight + 5;
setGeometry(0, 0, 400, y);
enableDebugger.onTick = []() {
debugger.enable(debugger.enableDebugger.checked());
};
onClose = []() {
debugger.enable(false);
return true;
};
}
void Debugger::setVisible(bool visible) {
Window::setVisible(visible);
console.setVisible(visible);
cpuDebugger.setVisible(visible);
}
void Debugger::enable(bool state) {
enableDebugger.setChecked(state);
}
void Debugger::run() {
if(enableDebugger.checked() == false) {
SNES::system.run();
return;
}
if(debugMode == DebugMode::None) {
usleep(20 * 1000);
return;
}
SNES::system.run();
if(debugMode == DebugMode::StepIntoCPU) {
if(SNES::debugger.break_event == SNES::Debugger::BreakEvent::CPUStep) {
debugMode = DebugMode::None;
cpuDebugger.eventStepInto();
console.eventTraceCPU();
}
}
SNES::debugger.break_event = SNES::Debugger::BreakEvent::None;
}
Debugger::Debugger() {
debugMode = DebugMode::None;
}
#endif

View File

@ -0,0 +1,21 @@
#include "console.hpp"
#include "cpu/debugger.hpp"
struct Debugger : TopLevelWindow {
enum class DebugMode : unsigned {
None,
StepIntoCPU,
} debugMode;
CheckBox enableDebugger;
CheckBox showMemoryEditor;
void create();
void setVisible(bool visible = true);
void enable(bool state);
void run();
Debugger();
};
extern Debugger debugger;

View File

@ -58,6 +58,11 @@ void FileBrowser::fileOpen(FileBrowser::Mode requestedMode, function<void (strin
filters.append(".sgb"); filters.append(".sgb");
break; break;
} }
case Mode::Filter: {
setTitle("Load Video Filter");
filters.append(".filter");
break;
}
case Mode::Shader: { case Mode::Shader: {
setTitle("Load Pixel Shader"); setTitle("Load Pixel Shader");
filters.append(".shader"); filters.append(".shader");

View File

@ -4,7 +4,7 @@ struct FileBrowser : TopLevelWindow {
Button upButton; Button upButton;
ListBox contentsBox; ListBox contentsBox;
enum class Mode : unsigned { Cartridge, Satellaview, SufamiTurbo, GameBoy, Shader } mode; enum class Mode : unsigned { Cartridge, Satellaview, SufamiTurbo, GameBoy, Filter, Shader } mode;
void fileOpen(Mode mode, function<void (string)> callback); void fileOpen(Mode mode, function<void (string)> callback);
void create(); void create();

View File

@ -96,6 +96,10 @@ void MainWindow::create() {
toolsSeparator2.create(tools); toolsSeparator2.create(tools);
toolsCheatEditor.create(tools, "Cheat Editor ..."); toolsCheatEditor.create(tools, "Cheat Editor ...");
toolsStateManager.create(tools, "State Manager ..."); toolsStateManager.create(tools, "State Manager ...");
#if defined(DEBUGGER)
toolsSeparator3.create(tools);
toolsDebugger.create(tools, "Debugger ...");
#endif
help.create(*this, "Help"); help.create(*this, "Help");
helpAbout.create(help, "About ..."); helpAbout.create(help, "About ...");
@ -192,6 +196,10 @@ void MainWindow::create() {
toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); }; toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); };
toolsStateManager.onTick = []() { stateManager.setVisible(); }; toolsStateManager.onTick = []() { stateManager.setVisible(); };
#if defined(DEBUGGER)
toolsDebugger.onTick = []() { debugger.setVisible(); };
#endif
helpAbout.onTick = []() { helpAbout.onTick = []() {
MessageWindow::information(mainWindow, { MessageWindow::information(mainWindow, {
"bsnes\n\n", "bsnes\n\n",

View File

@ -63,6 +63,8 @@ struct MainWindow : TopLevelWindow {
MenuSeparator toolsSeparator2; MenuSeparator toolsSeparator2;
MenuItem toolsCheatEditor; MenuItem toolsCheatEditor;
MenuItem toolsStateManager; MenuItem toolsStateManager;
MenuSeparator toolsSeparator3;
MenuItem toolsDebugger;
Menu help; Menu help;
MenuItem helpAbout; MenuItem helpAbout;
Viewport viewport; Viewport viewport;

View File

@ -28,6 +28,11 @@ void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) {
utility.showMessage({ "Slot ", activeSlot, " selected" }); utility.showMessage({ "Slot ", activeSlot, " selected" });
} }
//pause
if(scancode == keyboard(0)[Keyboard::P]) {
application.pause = !application.pause;
}
//fast forward //fast forward
if(scancode == keyboard(0)[Keyboard::Tilde]) { if(scancode == keyboard(0)[Keyboard::Tilde]) {
videoSync = config.video.synchronize; videoSync = config.video.synchronize;

View File

@ -1,4 +1,5 @@
Palette palette; Palette palette;
Filter filter;
Interface interface; Interface interface;
const uint8_t Palette::gammaRamp[32] = { const uint8_t Palette::gammaRamp[32] = {
@ -63,6 +64,20 @@ void Palette::update() {
} }
} }
void Filter::size(unsigned &width, unsigned &height) {
if(opened() && dl_size) return dl_size(width, height);
}
void Filter::render(uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch, unsigned width, unsigned height) {
if(opened() && dl_render) return dl_render(palette.color, output, outpitch, input, pitch, width, height);
for(unsigned y = 0; y < height; y++) {
uint32_t *outputLine = output + y * (outpitch >> 2);
const uint16_t *inputLine = input + y * (pitch >> 1);
for(unsigned x = 0; x < width; x++) *outputLine++ = palette.color[*inputLine++];
}
}
void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) { void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) {
bool interlace = (height >= 240); bool interlace = (height >= 240);
bool overscan = (height == 239 || height == 478); bool overscan = (height == 239 || height == 478);
@ -85,12 +100,11 @@ void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned hei
if(height == 448) height = 478; if(height == 448) height = 478;
} }
if(video.lock(buffer, outpitch, width, height)) { unsigned outwidth = width, outheight = height;
for(unsigned y = 0; y < height; y++) { filter.size(outwidth, outheight);
uint32_t *output = buffer + y * (outpitch >> 2);
const uint16_t *input = data + y * (inpitch >> 1); if(video.lock(buffer, outpitch, outwidth, outheight)) {
for(unsigned x = 0; x < width; x++) *output++ = palette.color[*input++]; filter.render(buffer, outpitch, data, inpitch, width, height);
}
video.unlock(); video.unlock();
video.refresh(); video.refresh();
} }

View File

@ -7,6 +7,13 @@ struct Palette {
void update(); void update();
}; };
struct Filter : public library {
function<void (unsigned&, unsigned&)> dl_size;
function<void (uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned)> dl_render;
void size(unsigned &width, unsigned &height);
void render(uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch, unsigned width, unsigned height);
};
struct Interface : public SNES::Interface { struct Interface : public SNES::Interface {
void video_refresh(const uint16_t *data, unsigned width, unsigned height); void video_refresh(const uint16_t *data, unsigned width, unsigned height);
void audio_sample(uint16_t left, uint16_t right); void audio_sample(uint16_t left, uint16_t right);
@ -15,4 +22,5 @@ struct Interface : public SNES::Interface {
}; };
extern Palette palette; extern Palette palette;
extern Filter filter;
extern Interface interface; extern Interface interface;

View File

@ -46,6 +46,10 @@ void Application::main(int argc, char **argv) {
advancedSettings.create(); advancedSettings.create();
cheatEditor.create(); cheatEditor.create();
stateManager.create(); stateManager.create();
#if defined(DEBUGGER)
debugger.create();
#endif
loadGeometry(); loadGeometry();
saveGeometry(); saveGeometry();
@ -86,6 +90,7 @@ void Application::main(int argc, char **argv) {
} }
utility.setControllers(); utility.setControllers();
utility.setFilter();
utility.setShader(); utility.setShader();
if(argc == 2) cartridge.loadNormal(argv[1]); if(argc == 2) cartridge.loadNormal(argv[1]);
@ -96,14 +101,15 @@ void Application::main(int argc, char **argv) {
utility.updateStatus(); utility.updateStatus();
if(SNES::cartridge.loaded()) { if(SNES::cartridge.loaded()) {
//pause emulator when main window is inactive? if(application.pause == true || (config.settings.focusPolicy == 0 && mainWindow.focused() == false)) {
if(config.settings.focusPolicy == 0) { usleep(20 * 1000);
if(mainWindow.focused() == false) { continue;
usleep(20 * 1000);
continue;
}
} }
#if defined(DEBUGGER)
debugger.run();
#else
SNES::system.run(); SNES::system.run();
#endif
} else { } else {
usleep(20 * 1000); usleep(20 * 1000);
} }
@ -129,6 +135,11 @@ void Application::addWindow(TopLevelWindow *window, const string &name, const st
geometryConfig.attach(window->position, window->name); geometryConfig.attach(window->position, window->name);
} }
Application::Application() {
pause = false;
quit = false;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
application.main(argc, argv); application.main(argc, argv);
return 0; return 0;

View File

@ -23,6 +23,15 @@ void VideoSettings::create() {
gammaRampCheck.create (*this, x, y, 430, Style::CheckBoxHeight, "Enable NTSC gamma ramp simulation"); y += Style::CheckBoxHeight + 5; gammaRampCheck.create (*this, x, y, 430, Style::CheckBoxHeight, "Enable NTSC gamma ramp simulation"); y += Style::CheckBoxHeight + 5;
filterLabel.create(*this, x, y, 340, Style::LabelHeight, "Video Filter :."); y += Style::LabelHeight + 5;
filterLabel.setFont(application.proportionalFontBold);
filterPath.create(*this, x, y, 430 - height - height - 10, height);
filterPath.setEditable(false);
filterPath.setText(config.video.filter);
filterClear.create(*this, x + 430 - height - height - 5, y, height, height, "");
filterSelect.create(*this, x + 430 - height, y, height, height, "..."); y += height + 5;
shaderLabel.create(*this, x, y, 340, Style::LabelHeight, "Pixel Shader :."); y += Style::LabelHeight + 5; shaderLabel.create(*this, x, y, 340, Style::LabelHeight, "Pixel Shader :."); y += Style::LabelHeight + 5;
shaderLabel.setFont(application.proportionalFontBold); shaderLabel.setFont(application.proportionalFontBold);
@ -42,6 +51,20 @@ void VideoSettings::create() {
contrastSlider.onChange = brightnessSlider.onChange = gammaSlider.onChange = gammaRampCheck.onTick = contrastSlider.onChange = brightnessSlider.onChange = gammaSlider.onChange = gammaRampCheck.onTick =
{ &VideoSettings::adjust, this }; { &VideoSettings::adjust, this };
filterClear.onTick = []() {
config.video.filter = "";
videoSettings.filterPath.setText(config.video.filter);
utility.setFilter();
};
filterSelect.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::Filter, [](string filename) {
config.video.filter = filename;
videoSettings.filterPath.setText(config.video.filter);
utility.setFilter();
});
};
shaderClear.onTick = []() { shaderClear.onTick = []() {
config.video.shader = ""; config.video.shader = "";
videoSettings.shaderPath.setText(config.video.shader); videoSettings.shaderPath.setText(config.video.shader);

View File

@ -10,6 +10,12 @@ struct VideoSettings : TopLevelWindow {
Label gammaValue; Label gammaValue;
HorizontalSlider gammaSlider; HorizontalSlider gammaSlider;
CheckBox gammaRampCheck; CheckBox gammaRampCheck;
Label filterLabel;
TextBox filterPath;
Button filterClear;
Button filterSelect;
Label shaderLabel; Label shaderLabel;
TextBox shaderPath; TextBox shaderPath;
Button shaderClear; Button shaderClear;

View File

@ -16,6 +16,10 @@ void Utility::updateStatus() {
text = statusMessage; text = statusMessage;
} else if(SNES::cartridge.loaded() == false) { } else if(SNES::cartridge.loaded() == false) {
text = "No cartridge loaded"; text = "No cartridge loaded";
} else if(application.pause) {
text = "Paused";
} else if(config.settings.focusPolicy == 0 && mainWindow.focused() == false) {
text = "Auto-paused";
} else { } else {
text = statusText; text = statusText;
} }
@ -71,6 +75,16 @@ void Utility::setScale(unsigned scale) {
mainWindow.setGeometry(geom.x, geom.y, width, height); mainWindow.setGeometry(geom.x, geom.y, width, height);
} }
void Utility::setFilter() {
if(filter.opened()) filter.close();
if(config.video.filter == "") return;
if(filter.open_absolute(config.video.filter)) {
filter.dl_size = filter.sym("filter_size");
filter.dl_render = filter.sym("filter_render");
if(!filter.dl_size || !filter.dl_render) filter.close();
}
}
void Utility::setShader() { void Utility::setShader() {
string data; string data;
data.readfile(config.video.shader); data.readfile(config.video.shader);

View File

@ -6,6 +6,7 @@ struct Utility : property<Utility> {
void setControllers(); void setControllers();
void setScale(unsigned scale = 0); void setScale(unsigned scale = 0);
void setFilter();
void setShader(); void setShader();
void cartridgeLoaded(); void cartridgeLoaded();

View File

@ -1,132 +1,32 @@
//2xSaI / Super 2xSaI / Super Eagle filter #include <nall/platform.hpp>
//authors: kode54 and Kreed #include <nall/stdint.hpp>
//license: GPL using namespace nall;
#include "2xsai.hpp"
#include "implementation.cpp" #include "implementation.cpp"
//===== extern "C" {
//2xSaI void filter_size(unsigned&, unsigned&);
//===== void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
void _2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width; uint32_t temp[512 * 480];
outheight = height;
dllexport void filter_size(unsigned &width, unsigned &height) {
if(width <= 256 && height <= 240) { width *= 2;
outwidth *= 2; height *= 2;
outheight *= 2;
}
}
void _2xSaIFilter::render(
uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, width, height);
return;
}
for(unsigned y = 0; y < height; y++) {
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
uint32_t *line_out = temp + y * 256;
for(unsigned x = 0; x < width; x++) {
line_out[x] = colortable[line_in[x]];
}
}
_2xSaI32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
}
_2xSaIFilter::_2xSaIFilter() {
temp = new uint32_t[256*240];
}
_2xSaIFilter::~_2xSaIFilter() {
delete[] temp;
} }
//=========== dllexport void filter_render(
//Super 2xSaI uint32_t *colortable, uint32_t *output, unsigned outpitch,
//=========== const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
void Super2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { for(unsigned y = 0; y < height; y++) {
outwidth = width; const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
outheight = height; uint32_t *line_out = temp + y * width;
for(unsigned x = 0; x < width; x++) {
if(width <= 256 && height <= 240) { line_out[x] = colortable[line_in[x]];
outwidth *= 2; }
outheight *= 2; }
}
}
void Super2xSaIFilter::render(
uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, width, height);
return;
}
for(unsigned y = 0; y < height; y++) {
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
uint32_t *line_out = temp + y * 256;
for(unsigned x = 0; x < width; x++) {
line_out[x] = colortable[line_in[x]];
}
}
Super2xSaI32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
}
Super2xSaIFilter::Super2xSaIFilter() {
temp = new uint32_t[256*240];
}
Super2xSaIFilter::~Super2xSaIFilter() {
delete[] temp;
}
//=========== _2xSaI32( (unsigned char *) temp, 2048, 0, (unsigned char *) output, outpitch, width, height );
//Super Eagle
//===========
void SuperEagleFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void SuperEagleFilter::render(
uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, width, height);
return;
}
for(unsigned y = 0; y < height; y++) {
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
uint32_t *line_out = temp + y * 256;
for(unsigned x = 0; x < width; x++) {
line_out[x] = colortable[line_in[x]];
}
}
SuperEagle32( (unsigned char *) temp, 1024, 0, (unsigned char *) output, outpitch, width, height );
}
SuperEagleFilter::SuperEagleFilter() {
temp = new uint32_t[256*240];
}
SuperEagleFilter::~SuperEagleFilter() {
delete[] temp;
} }

View File

@ -1,35 +0,0 @@
class _2xSaIFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
_2xSaIFilter();
~_2xSaIFilter();
private:
uint32_t *temp;
} filter_2xsai;
class Super2xSaIFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
Super2xSaIFilter();
~Super2xSaIFilter();
private:
uint32_t *temp;
} filter_super2xsai;
class SuperEagleFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
SuperEagleFilter();
~SuperEagleFilter();
private:
uint32_t *temp;
} filter_supereagle;

View File

@ -0,0 +1,32 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
#include "implementation.cpp"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
uint32_t temp[512 * 480];
dllexport void filter_size(unsigned &width, unsigned &height) {
width *= 2;
height *= 2;
}
dllexport void filter_render(
uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
for(unsigned y = 0; y < height; y++) {
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
uint32_t *line_out = temp + y * width;
for(unsigned x = 0; x < width; x++) {
line_out[x] = colortable[line_in[x]];
}
}
Super2xSaI32( (unsigned char *) temp, 2048, 0, (unsigned char *) output, outpitch, width, height );
}

View File

@ -0,0 +1,32 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
#include "implementation.cpp"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
uint32_t temp[512 * 480];
dllexport void filter_size(unsigned &width, unsigned &height) {
width *= 2;
height *= 2;
}
dllexport void filter_render(
uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
for(unsigned y = 0; y < height; y++) {
const uint16_t *line_in = (const uint16_t *) (((const uint8_t*)input) + pitch * y);
uint32_t *line_out = temp + y * width;
for(unsigned x = 0; x < width; x++) {
line_out[x] = colortable[line_in[x]];
}
}
SuperEagle32( (unsigned char *) temp, 2048, 0, (unsigned char *) output, outpitch, width, height );
}

View File

@ -1,89 +1,51 @@
include nall/Makefile include nall/Makefile
qtlibs := QtCore QtGui c := $(compiler) -std=gnu99
include nall/qt/Makefile cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
flags := -O3 -I. -Iobj -fomit-frame-pointer -fPIC
link := -s
objects :=
c := $(compiler) -std=gnu99 objects += out/pixellate2x.filter
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x objects += out/scanline-00.filter
flags := -O3 -I. -Iobj -fomit-frame-pointer $(qtinc) objects += out/scanline-25.filter
link := objects += out/scanline-50.filter
objects += out/scanline-75.filter
objects += out/scale2x.filter
objects += out/2xsai.filter
objects += out/super-2xsai.filter
objects += out/super-eagle.filter
objects += out/lq2x.filter
objects += out/hq2x.filter
objects += out/ntsc-rf.filter
objects += out/ntsc-composite.filter
objects += out/ntsc-svideo.filter
objects += out/ntsc-rgb.filter
ifeq ($(platform),x) compile = $(cpp) $(link) $(flags) -o $@ -shared $<
flags := -fPIC -fopenmp $(flags)
link += -s -fopenmp -lpthread -lgomp
else ifeq ($(platform),osx)
flags := -fPIC -fopenmp $(flags)
link += -fopenmp -lpthread -lgomp
else ifeq ($(platform),win)
flags := -fopenmp $(flags)
link += -fopenmp -lpthread
endif
objects := snesfilter %.filter: $<; $(call compile)
compile = \
$(strip \
$(if $(filter %.c,$<), \
$(c) $(flags) $1 -c $< -o $@, \
$(if $(filter %.cpp,$<), \
$(cpp) $(flags) $1 -c $< -o $@ \
) \
) \
)
%.o: $<; $(call compile)
all: build; all: build;
objects := $(patsubst %,obj/%.o,$(objects)) out/pixellate2x.filter: pixellate2x/pixellate2x.cpp pixellate2x/*
moc_headers := $(call rwildcard,./,%.moc.hpp) out/scanline-00.filter: scanline/scanline-00.cpp scanline/*
moc_objects := $(foreach f,$(moc_headers),obj/$(notdir $(patsubst %.moc.hpp,%.moc,$f))) out/scanline-25.filter: scanline/scanline-25.cpp scanline/*
out/scanline-50.filter: scanline/scanline-50.cpp scanline/*
out/scanline-75.filter: scanline/scanline-75.cpp scanline/*
out/scale2x.filter: scale2x/scale2x.cpp scale2x/*
out/2xsai.filter: 2xsai/2xsai.cpp 2xsai/*
out/super-2xsai.filter: 2xsai/super-2xsai.cpp 2xsai/*
out/super-eagle.filter: 2xsai/super-eagle.cpp 2xsai/*
out/lq2x.filter: lq2x/lq2x.cpp lq2x/*
out/hq2x.filter: hq2x/hq2x.cpp hq2x/*
out/ntsc-rf.filter: ntsc/ntsc-rf.cpp ntsc/*
out/ntsc-composite.filter: ntsc/ntsc-composite.cpp ntsc/*
out/ntsc-svideo.filter: ntsc/ntsc-svideo.cpp ntsc/*
out/ntsc-rgb.filter: ntsc/ntsc-rgb.cpp ntsc/*
# automatically run moc on all .moc.hpp (MOC header) files build: $(objects)
%.moc: $<; $(moc) -i $< -o $@
# automatically generate %.moc build rules
__list = $(moc_headers)
$(foreach f,$(moc_objects), \
$(eval __file = $(word 1,$(__list))) \
$(eval __list = $(wordlist 2,$(words $(__list)),$(__list))) \
$(eval $f: $(__file)) \
)
##################
### snesfilter ###
##################
obj/snesfilter.o: snesfilter.cpp *
###############
### targets ###
###############
build: $(moc_objects) $(objects)
ifeq ($(platform),x)
ar rcs libsnesfilter.a $(objects)
$(cpp) $(link) -o libsnesfilter.so -shared -Wl,-soname,libsnesfilter.so.1 $(objects) $(qtlib)
else ifeq ($(platform),osx)
ar rcs libsnesfilter.a $(objects)
$(cpp) $(link) -o libsnesfilter.dylib -shared -dynamiclib $(objects) $(qtlib)
else ifeq ($(platform),win)
$(cpp) $(link) -o snesfilter.dll -shared -Wl,--out-implib,libsnesfilter.a $(objects) $(qtlib)
endif
install: install:
ifeq ($(platform),x)
install -D -m 755 libsnesfilter.a $(DESTDIR)$(prefix)/lib
install -D -m 755 libsnesfilter.so $(DESTDIR)$(prefix)/lib
ldconfig -n $(DESTDIR)$(prefix)/lib
else ifeq ($(platform),osx)
cp libsnesfilter.dylib /usr/local/lib/libsnesfilter.dylib
endif
clean: clean:
-@$(call delete,obj/*.o)
-@$(call delete,obj/*.moc)
-@$(call delete,libsnesfilter.a)
-@$(call delete,libsnesfilter.so)
-@$(call delete,libsnesfilter.dylib)
-@$(call delete,snesfilter.dll)

View File

@ -1,2 +0,0 @@
@mingw32-make
@pause

View File

@ -1 +0,0 @@
@mingw32-make clean

View File

@ -1,23 +0,0 @@
#include "direct.hpp"
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render(
uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch,
unsigned width, unsigned height
) {
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
}
input += pitch - width;
output += outpitch - width;
}
}

View File

@ -1,5 +0,0 @@
class DirectFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
} filter_direct;

View File

@ -1,31 +1,157 @@
//HQ2x filter #include <nall/platform.hpp>
//authors: byuu and blargg #include <nall/stdint.hpp>
//license: public domain using namespace nall;
//
//note: this is a clean reimplementation of the original HQ2x filter, which was
//written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
#include "hq2x.hpp" extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { enum {
if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407,
outwidth = width * 2; diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0,
outheight = height * 2; };
}
void HQ2xFilter::render( uint32_t *yuvTable;
uint32_t *output, unsigned outpitch, uint8_t rotate[256];
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) { const uint8_t hqTable[256] = {
if(width > 256 || height > 240) { 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
filter_direct.render(output, outpitch, input, pitch, width, height); 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
return; 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
};
static void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31;
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888
double r = (R << 3) | (R >> 2);
double g = (G << 3) | (G >> 2);
double b = (B << 3) | (B >> 2);
//bgr888->yuv888
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
} }
for(unsigned n = 0; n < 256; n++) {
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
}
}
static void terminate() {
delete[] yuvTable;
}
static bool same(uint16_t x, uint16_t y) {
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
}
static bool diff(uint32_t x, uint16_t y) {
return ((x - yuvTable[y]) & diff_mask);
}
static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
static uint16_t blend1(uint32_t A, uint32_t B) {
grow(A); grow(B);
A = (A * 3 + B) >> 2;
return pack(A);
}
static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + B + C) >> 2);
}
static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 5 + B * 2 + C) >> 3);
}
static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 6 + B + C) >> 3);
}
static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + (B + C) * 3) >> 3);
}
static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 14 + B + C) >> 4);
}
static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
switch(rule) { default:
case 0: return E;
case 1: return blend1(E, A);
case 2: return blend1(E, D);
case 3: return blend1(E, B);
case 4: return blend2(E, D, B);
case 5: return blend2(E, A, B);
case 6: return blend2(E, A, D);
case 7: return blend3(E, B, D);
case 8: return blend3(E, D, B);
case 9: return blend4(E, D, B);
case 10: return blend5(E, D, B);
case 11: return blend6(E, D, B);
case 12: return same(B, D) ? blend2(E, D, B) : E;
case 13: return same(B, D) ? blend5(E, D, B) : E;
case 14: return same(B, D) ? blend6(E, D, B) : E;
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
}
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
width *= 2;
height *= 2;
}
dllexport void filter_render(
uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
pitch >>= 1; pitch >>= 1;
outpitch >>= 2; outpitch >>= 2;
#pragma omp parallel for //#pragma omp parallel for
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * pitch; const uint16_t *in = input + y * pitch;
uint32_t *out0 = output + y * outpitch * 2; uint32_t *out0 = output + y * outpitch * 2;
@ -38,7 +164,7 @@ void HQ2xFilter::render(
*out0++ = 0; *out0++ = 0; *out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0; *out1++ = 0; *out1++ = 0;
for(unsigned x = 1; x < 256 - 1; x++) { for(unsigned x = 1; x < width - 1; x++) {
uint16_t A = *(in - prevline - 1); uint16_t A = *(in - prevline - 1);
uint16_t B = *(in - prevline + 0); uint16_t B = *(in - prevline + 0);
uint16_t C = *(in - prevline + 1); uint16_t C = *(in - prevline + 1);
@ -75,121 +201,3 @@ void HQ2xFilter::render(
*out1++ = 0; *out1++ = 0; *out1++ = 0; *out1++ = 0;
} }
} }
HQ2xFilter::HQ2xFilter() {
yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31;
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888
double r = (R << 3) | (R >> 2);
double g = (G << 3) | (G >> 2);
double b = (B << 3) | (B >> 2);
//bgr888->yuv888
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
}
for(unsigned n = 0; n < 256; n++) {
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
}
}
HQ2xFilter::~HQ2xFilter() {
delete[] yuvTable;
}
bool HQ2xFilter::same(uint16_t x, uint16_t y) {
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
}
bool HQ2xFilter::diff(uint32_t x, uint16_t y) {
return ((x - yuvTable[y]) & diff_mask);
}
void HQ2xFilter::grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
uint16_t HQ2xFilter::pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
uint16_t HQ2xFilter::blend1(uint32_t A, uint32_t B) {
grow(A); grow(B);
A = (A * 3 + B) >> 2;
return pack(A);
}
uint16_t HQ2xFilter::blend2(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + B + C) >> 2);
}
uint16_t HQ2xFilter::blend3(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 5 + B * 2 + C) >> 3);
}
uint16_t HQ2xFilter::blend4(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 6 + B + C) >> 3);
}
uint16_t HQ2xFilter::blend5(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + (B + C) * 3) >> 3);
}
uint16_t HQ2xFilter::blend6(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 14 + B + C) >> 4);
}
uint16_t HQ2xFilter::blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
switch(rule) { default:
case 0: return E;
case 1: return blend1(E, A);
case 2: return blend1(E, D);
case 3: return blend1(E, B);
case 4: return blend2(E, D, B);
case 5: return blend2(E, A, B);
case 6: return blend2(E, A, D);
case 7: return blend3(E, B, D);
case 8: return blend3(E, D, B);
case 9: return blend4(E, D, B);
case 10: return blend5(E, D, B);
case 11: return blend6(E, D, B);
case 12: return same(B, D) ? blend2(E, D, B) : E;
case 13: return same(B, D) ? blend5(E, D, B) : E;
case 14: return same(B, D) ? blend6(E, D, B) : E;
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
}
}
const uint8_t HQ2xFilter::hqTable[256] = {
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
};

View File

@ -1,30 +0,0 @@
class HQ2xFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
HQ2xFilter();
~HQ2xFilter();
private:
enum {
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407,
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0,
};
static const uint8_t hqTable[256];
uint32_t *yuvTable;
uint8_t rotate[256];
alwaysinline bool same(uint16_t x, uint16_t y);
alwaysinline bool diff(uint32_t x, uint16_t y);
alwaysinline void grow(uint32_t &n);
alwaysinline uint16_t pack(uint32_t n);
alwaysinline uint16_t blend1(uint32_t A, uint32_t B);
alwaysinline uint16_t blend2(uint32_t A, uint32_t B, uint32_t C);
alwaysinline uint16_t blend3(uint32_t A, uint32_t B, uint32_t C);
alwaysinline uint16_t blend4(uint32_t A, uint32_t B, uint32_t C);
alwaysinline uint16_t blend5(uint32_t A, uint32_t B, uint32_t C);
alwaysinline uint16_t blend6(uint32_t A, uint32_t B, uint32_t C);
alwaysinline uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H);
} filter_hq2x;

View File

@ -1,20 +1,21 @@
#include "lq2x.hpp" #include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { extern "C" {
if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); void filter_size(unsigned&, unsigned&);
outwidth = width * 2; void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
outheight = height * 2; };
dllexport void filter_size(unsigned &width, unsigned &height) {
width *= 2;
height *= 2;
} }
void LQ2xFilter::render( dllexport void filter_render(
uint32_t *output, unsigned outpitch, uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) { ) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, width, height);
return;
}
pitch >>= 1; pitch >>= 1;
outpitch >>= 2; outpitch >>= 2;
@ -27,9 +28,9 @@ void LQ2xFilter::render(
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t A = *(input - prevline); uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input; uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input; uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input; uint16_t D = (x < width - 1) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline); uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C]; uint32_t c = colortable[C];
@ -47,7 +48,7 @@ void LQ2xFilter::render(
} }
input += pitch - width; input += pitch - width;
out0 += outpitch + outpitch - 512; out0 += outpitch + outpitch - (width << 1);
out1 += outpitch + outpitch - 512; out1 += outpitch + outpitch - (width << 1);
} }
} }

View File

@ -1,5 +0,0 @@
class LQ2xFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
} filter_lq2x;

View File

@ -29,10 +29,12 @@ ifeq ($(platform),)
endif endif
ifeq ($(compiler),) ifeq ($(compiler),)
ifeq ($(platform),osx) ifeq ($(platform),win)
compiler := gcc-mp-4.4
else
compiler := gcc compiler := gcc
else ifeq ($(platform),osx)
compiler := gcc-mp-4.5
else
compiler := gcc-4.5
endif endif
endif endif

View File

@ -49,7 +49,7 @@ namespace nall {
case signed_t: *(signed*)data = strsigned(s); break; case signed_t: *(signed*)data = strsigned(s); break;
case unsigned_t: *(unsigned*)data = strunsigned(s); break; case unsigned_t: *(unsigned*)data = strunsigned(s); break;
case double_t: *(double*)data = strdouble(s); break; case double_t: *(double*)data = strdouble(s); break;
case string_t: trim(s, "\""); *(string*)data = s; break; case string_t: s.trim("\""); *(string*)data = s; break;
} }
} }
}; };
@ -83,8 +83,8 @@ namespace nall {
lstring part; lstring part;
part.qsplit(" = ", line[i]); part.qsplit(" = ", line[i]);
trim(part[0]); part[0].trim();
trim(part[1]); part[1].trim();
for(unsigned n = 0; n < list.size(); n++) { for(unsigned n = 0; n < list.size(); n++) {
if(part[0] == list[n].name) { if(part[0] == list[n].name) {
@ -102,7 +102,7 @@ namespace nall {
virtual bool save(const char *filename) const { virtual bool save(const char *filename) const {
file fp; file fp;
if(fp.open(filename, file::mode_write)) { if(fp.open(filename, file::mode::write)) {
for(unsigned i = 0; i < list.size(); i++) { for(unsigned i = 0; i < list.size(); i++) {
string output; string output;
output << list[i].name << " = " << list[i].get(); output << list[i].name << " = " << list[i].get();

View File

@ -27,7 +27,7 @@ namespace nall {
bool import(const char *filename) { bool import(const char *filename) {
string data; string data;
if(data.readfile(filename) == false) return false; if(data.readfile(filename) == false) return false;
ltrim_once(data, "\xef\xbb\xbf"); //remove UTF-8 marker, if it exists data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
data.replace("\r", ""); data.replace("\r", "");
lstring line; lstring line;
@ -39,12 +39,12 @@ namespace nall {
if(part.size() != 2) continue; if(part.size() != 2) continue;
//remove whitespace //remove whitespace
trim(part[0]); part[0].trim();
trim(part[1]); part[1].trim();
//remove quotes //remove quotes
trim_once(part[0], "\""); part[0].trim<1>("\"");
trim_once(part[1], "\""); part[1].trim<1>("\"");
unsigned n = index_input.size(); unsigned n = index_input.size();
index_input[n] = part[0]; index_input[n] = part[0];

151
snesfilter/nall/directory.hpp Executable file
View File

@ -0,0 +1,151 @@
#ifndef NALL_DIRECTORY_HPP
#define NALL_DIRECTORY_HPP
#include <nall/foreach.hpp>
#include <nall/sort.hpp>
#include <nall/string.hpp>
#if defined(_WIN32)
#include <nall/utf8.hpp>
#else
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#endif
namespace nall {
struct directory {
static bool exists(const string &pathname);
static lstring folders(const string &pathname, const string &pattern = "*");
static lstring files(const string &pathname, const string &pattern = "*");
static lstring contents(const string &pathname, const string &pattern = "*");
};
#if defined(_WIN32)
inline bool directory::exists(const string &pathname) {
DWORD result = GetFileAttributes(utf16_t(pathname));
if(result == INVALID_FILE_ATTRIBUTES) return false;
return (result & FILE_ATTRIBUTE_DIRECTORY);
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
foreach(file, files) folders.append(file);
return folders;
}
#else
inline bool directory::exists(const string &pathname) {
DIR *dp = opendir(pathname);
if(!dp) return false;
closedir(dp);
return true;
}
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if((ep->d_type & DT_DIR) == 0) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
foreach(file, files) folders.append(file);
return folders;
}
#endif
}
#endif

View File

@ -3,9 +3,9 @@
//dynamic linking support //dynamic linking support
#include <string.h>
#include <nall/detect.hpp> #include <nall/detect.hpp>
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp> #include <nall/utility.hpp>
#if defined(PLATFORM_X) || defined(PLATFORM_OSX) #if defined(PLATFORM_X) || defined(PLATFORM_OSX)
@ -18,7 +18,7 @@
namespace nall { namespace nall {
struct library { struct library {
bool opened() const { return handle; } bool opened() const { return handle; }
bool open(const char*); bool open(const char*, const char* = "");
void* sym(const char*); void* sym(const char*);
void close(); void close();
@ -33,20 +33,10 @@ namespace nall {
}; };
#if defined(PLATFORM_X) #if defined(PLATFORM_X)
inline bool library::open(const char *name) { inline bool library::open(const char *name, const char *path) {
if(handle) close(); if(handle) close();
char *t = new char[strlen(name) + 256]; handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
strcpy(t, "lib"); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
strcat(t, name);
strcat(t, ".so");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
if(!handle) {
strcpy(t, "/usr/local/lib/lib");
strcat(t, name);
strcat(t, ".so");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
}
delete[] t;
return handle; return handle;
} }
@ -61,20 +51,10 @@ namespace nall {
handle = 0; handle = 0;
} }
#elif defined(PLATFORM_OSX) #elif defined(PLATFORM_OSX)
inline bool library::open(const char *name) { inline bool library::open(const char *name, const char *path) {
if(handle) close(); if(handle) close();
char *t = new char[strlen(name) + 256]; handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
strcpy(t, "lib"); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
strcat(t, name);
strcat(t, ".dylib");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
if(!handle) {
strcpy(t, "/usr/local/lib/lib");
strcat(t, name);
strcat(t, ".dylib");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
}
delete[] t;
return handle; return handle;
} }
@ -89,13 +69,10 @@ namespace nall {
handle = 0; handle = 0;
} }
#elif defined(PLATFORM_WIN) #elif defined(PLATFORM_WIN)
inline bool library::open(const char *name) { inline bool library::open(const char *name, const char *path) {
if(handle) close(); if(handle) close();
char *t = new char[strlen(name) + 8]; string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll");
strcpy(t, name); handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
strcat(t, ".dll");
handle = (uintptr_t)LoadLibraryW(utf16_t(t));
delete[] t;
return handle; return handle;
} }
@ -110,7 +87,7 @@ namespace nall {
handle = 0; handle = 0;
} }
#else #else
inline bool library::open(const char*) { return false; } inline bool library::open(const char*, const char*) { return false; }
inline void* library::sym(const char*) { return 0; } inline void* library::sym(const char*) { return 0; }
inline void library::close() {} inline void library::close() {}
#endif #endif

View File

@ -11,6 +11,7 @@
#endif #endif
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utf8.hpp> #include <nall/utf8.hpp>
#include <nall/utility.hpp> #include <nall/utility.hpp>
@ -25,12 +26,12 @@ namespace nall {
class file { class file {
public: public:
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread }; enum class mode : unsigned { read, write, readwrite, writeread };
enum SeekMode { seek_absolute, seek_relative }; enum class index : unsigned { absolute, relative };
uint8_t read() { uint8_t read() {
if(!fp) return 0xff; //file not open if(!fp) return 0xff; //file not open
if(file_mode == mode_write) return 0xff; //reads not permitted if(file_mode == mode::write) return 0xff; //reads not permitted
if(file_offset >= file_size) return 0xff; //cannot read past end of file if(file_offset >= file_size) return 0xff; //cannot read past end of file
buffer_sync(); buffer_sync();
return buffer[(file_offset++) & buffer_mask]; return buffer[(file_offset++) & buffer_mask];
@ -58,8 +59,8 @@ namespace nall {
} }
void write(uint8_t data) { void write(uint8_t data) {
if(!fp) return; //file not open if(!fp) return; //file not open
if(file_mode == mode_read) return; //writes not permitted if(file_mode == mode::read) return; //writes not permitted
buffer_sync(); buffer_sync();
buffer[(file_offset++) & buffer_mask] = data; buffer[(file_offset++) & buffer_mask] = data;
buffer_dirty = true; buffer_dirty = true;
@ -83,9 +84,10 @@ namespace nall {
while(length--) write(*buffer++); while(length--) write(*buffer++);
} }
void print(const char *string) { template<typename... Args> void print(Args... args) {
if(!string) return; string data(args...);
while(*string) write(*string++); const char *p = data;
while(*p) write(*p++);
} }
void flush() { void flush() {
@ -93,19 +95,19 @@ namespace nall {
fflush(fp); fflush(fp);
} }
void seek(int offset, SeekMode mode = seek_absolute) { void seek(int offset, index index_ = index::absolute) {
if(!fp) return; //file not open if(!fp) return; //file not open
buffer_flush(); buffer_flush();
uintmax_t req_offset = file_offset; uintmax_t req_offset = file_offset;
switch(mode) { switch(index_) {
case seek_absolute: req_offset = offset; break; case index::absolute: req_offset = offset; break;
case seek_relative: req_offset += offset; break; case index::relative: req_offset += offset; break;
} }
if(req_offset < 0) req_offset = 0; //cannot seek before start of file if(req_offset < 0) req_offset = 0; //cannot seek before start of file
if(req_offset > file_size) { if(req_offset > file_size) {
if(file_mode == mode_read) { //cannot seek past end of file if(file_mode == mode::read) { //cannot seek past end of file
req_offset = file_size; req_offset = file_size;
} else { //pad file to requested location } else { //pad file to requested location
file_offset = file_size; file_offset = file_size;
@ -172,20 +174,20 @@ namespace nall {
return fp; return fp;
} }
bool open(const char *fn, FileMode mode) { bool open(const char *fn, mode mode_) {
if(fp) return false; if(fp) return false;
switch(file_mode = mode) { switch(file_mode = mode_) {
#if !defined(_WIN32) #if !defined(_WIN32)
case mode_read: fp = fopen(fn, "rb"); break; case mode::read: fp = fopen(fn, "rb"); break;
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
case mode_readwrite: fp = fopen(fn, "rb+"); break; case mode::readwrite: fp = fopen(fn, "rb+"); break;
case mode_writeread: fp = fopen(fn, "wb+"); break; case mode::writeread: fp = fopen(fn, "wb+"); break;
#else #else
case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break; case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break; case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break; case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break; case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
#endif #endif
} }
if(!fp) return false; if(!fp) return false;
@ -211,7 +213,7 @@ namespace nall {
fp = 0; fp = 0;
file_offset = 0; file_offset = 0;
file_size = 0; file_size = 0;
file_mode = mode_read; file_mode = mode::read;
} }
~file() { ~file() {
@ -229,7 +231,7 @@ namespace nall {
FILE *fp; FILE *fp;
unsigned file_offset; unsigned file_offset;
unsigned file_size; unsigned file_size;
FileMode file_mode; mode file_mode;
void buffer_sync() { void buffer_sync() {
if(!fp) return; //file not open if(!fp) return; //file not open
@ -243,14 +245,14 @@ namespace nall {
} }
void buffer_flush() { void buffer_flush() {
if(!fp) return; //file not open if(!fp) return; //file not open
if(file_mode == mode_read) return; //buffer cannot be written to if(file_mode == mode::read) return; //buffer cannot be written to
if(buffer_offset < 0) return; //buffer unused if(buffer_offset < 0) return; //buffer unused
if(buffer_dirty == false) return; //buffer unmodified since read if(buffer_dirty == false) return; //buffer unmodified since read
fseek(fp, buffer_offset, SEEK_SET); fseek(fp, buffer_offset, SEEK_SET);
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
if(length) unsigned unused = fwrite(buffer, 1, length, fp); if(length) unsigned unused = fwrite(buffer, 1, length, fp);
buffer_offset = -1; //invalidate buffer buffer_offset = -1; //invalidate buffer
buffer_dirty = false; buffer_dirty = false;
} }
}; };

View File

@ -19,14 +19,16 @@
namespace nall { namespace nall {
class filemap { class filemap {
public: public:
enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread }; enum class mode : unsigned { read, write, readwrite, writeread };
bool open(const char *filename, filemode mode) { return p_open(filename, mode); } bool opened() const { return p_opened(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); } void close() { return p_close(); }
unsigned size() const { return p_size; } unsigned size() const { return p_size; }
uint8_t* handle() { return p_handle; } uint8_t* data() { return p_handle; }
const uint8_t* handle() const { return p_handle; } const uint8_t* data() const { return p_handle; }
filemap() : p_size(0), p_handle(0) { p_ctor(); } filemap() : p_size(0), p_handle(0) { p_ctor(); }
filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); }
~filemap() { p_dtor(); } ~filemap() { p_dtor(); }
private: private:
@ -40,31 +42,35 @@ namespace nall {
HANDLE p_filehandle, p_maphandle; HANDLE p_filehandle, p_maphandle;
bool p_open(const char *filename, filemode mode) { bool p_opened() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
int desired_access, creation_disposition, flprotect, map_access; int desired_access, creation_disposition, flprotect, map_access;
switch(mode) { switch(mode_) {
default: return false; default: return false;
case mode_read: case mode::read:
desired_access = GENERIC_READ; desired_access = GENERIC_READ;
creation_disposition = OPEN_EXISTING; creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READONLY; flprotect = PAGE_READONLY;
map_access = FILE_MAP_READ; map_access = FILE_MAP_READ;
break; break;
case mode_write: case mode::write:
//write access requires read access //write access requires read access
desired_access = GENERIC_WRITE; desired_access = GENERIC_WRITE;
creation_disposition = CREATE_ALWAYS; creation_disposition = CREATE_ALWAYS;
flprotect = PAGE_READWRITE; flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS; map_access = FILE_MAP_ALL_ACCESS;
break; break;
case mode_readwrite: case mode::readwrite:
desired_access = GENERIC_READ | GENERIC_WRITE; desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = OPEN_EXISTING; creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READWRITE; flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS; map_access = FILE_MAP_ALL_ACCESS;
break; break;
case mode_writeread: case mode::writeread:
desired_access = GENERIC_READ | GENERIC_WRITE; desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = CREATE_NEW; creation_disposition = CREATE_NEW;
flprotect = PAGE_READWRITE; flprotect = PAGE_READWRITE;
@ -122,30 +128,34 @@ namespace nall {
int p_fd; int p_fd;
bool p_open(const char *filename, filemode mode) { bool p_opened() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
int open_flags, mmap_flags; int open_flags, mmap_flags;
switch(mode) { switch(mode_) {
default: return false; default: return false;
case mode_read: case mode::read:
open_flags = O_RDONLY; open_flags = O_RDONLY;
mmap_flags = PROT_READ; mmap_flags = PROT_READ;
break; break;
case mode_write: case mode::write:
open_flags = O_RDWR | O_CREAT; //mmap() requires read access open_flags = O_RDWR | O_CREAT; //mmap() requires read access
mmap_flags = PROT_WRITE; mmap_flags = PROT_WRITE;
break; break;
case mode_readwrite: case mode::readwrite:
open_flags = O_RDWR; open_flags = O_RDWR;
mmap_flags = PROT_READ | PROT_WRITE; mmap_flags = PROT_READ | PROT_WRITE;
break; break;
case mode_writeread: case mode::writeread:
open_flags = O_RDWR | O_CREAT; open_flags = O_RDWR | O_CREAT;
mmap_flags = PROT_READ | PROT_WRITE; mmap_flags = PROT_READ | PROT_WRITE;
break; break;
} }
p_fd = ::open(filename, open_flags); p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(p_fd < 0) return false; if(p_fd < 0) return false;
struct stat p_stat; struct stat p_stat;

View File

@ -1,89 +1,59 @@
#ifndef NALL_FUNCTION_HPP #ifndef NALL_FUNCTION_HPP
#define NALL_FUNCTION_HPP #define NALL_FUNCTION_HPP
#include <functional>
#include <type_traits>
namespace nall { namespace nall {
template<typename T> class function; template<typename T> class function;
template<typename R, typename... P> template<typename R, typename... P> class function<R (P...)> {
class function<R (P...)> { struct container {
private: virtual R operator()(P... p) const = 0;
struct base1 { virtual void func1(P...) {} }; virtual container* copy() const = 0;
struct base2 { virtual void func2(P...) {} }; virtual ~container() {}
struct derived : base1, virtual base2 {}; } *callback;
struct data_t { struct global : container {
R (*callback)(const data_t&, P...); R (*function)(P...);
union { R operator()(P... p) const { return function(std::forward<P>(p)...); }
R (*callback_global)(P...); container* copy() const { return new global(function); }
struct { global(R (*function)(P...)) : function(function) {}
R (derived::*callback_member)(P...); };
void *object;
};
};
} data;
static R callback_global(const data_t &data, P... p) { template<typename C> struct member : container {
return data.callback_global(p...); R (C::*function)(P...);
} C *object;
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
container* copy() const { return new member(function, object); }
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
};
template<typename C> template<typename L> struct lambda : container {
static R callback_member(const data_t &data, P... p) { L object;
return (((C*)data.object)->*((R (C::*&)(P...))data.callback_member))(p...); R operator()(P... p) const { return object(std::forward<P>(p)...); }
} container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
};
public: public:
R operator()(P... p) const { return data.callback(data, p...); } operator bool() const { return callback; }
operator bool() const { return data.callback; } R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
void reset() { data.callback = 0; } void reset() { if(callback) { delete callback; callback = 0; } }
function& operator=(const function &source) {
if(this != &source) {
if(callback) { delete callback; callback = 0; }
if(source.callback) callback = source.callback->copy();
}
return *this;
}
function& operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
function(const function &source) { operator=(source); } function(const function &source) { operator=(source); }
function() : callback(0) {}
//no pointer function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
function() { function(R (*function)(P...)) { callback = new global(function); }
data.callback = 0; template<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
} template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }
template<typename L> function(const L& object) { callback = new lambda<L>(object); }
//symbolic link pointer (nall/dl.hpp::sym, etc) ~function() { if(callback) delete callback; }
function(void *callback) {
data.callback = callback ? &callback_global : 0;
data.callback_global = (R (*)(P...))callback;
}
//global function pointer
function(R (*callback)(P...)) {
data.callback = &callback_global;
data.callback_global = callback;
}
//member function pointer
template<typename C>
function(R (C::*callback)(P...), C *object) {
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
data.callback = &callback_member<C>;
(R (C::*&)(P...))data.callback_member = callback;
data.object = object;
}
//const member function pointer
template<typename C>
function(R (C::*callback)(P...) const, C *object) {
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
data.callback = &callback_member<C>;
(R (C::*&)(P...))data.callback_member = (R (C::*&)(P...))callback;
data.object = object;
}
//lambda function pointer
template<typename T>
function(T callback) {
static_assert(std::is_same<R, typename std::result_of<T(P...)>::type>::value, "lambda mismatch");
data.callback = &callback_global;
data.callback_global = (R (*)(P...))callback;
}
}; };
} }

View File

@ -91,7 +91,7 @@ struct Keyboard {
static uint16_t decode(const char *name) { static uint16_t decode(const char *name) {
string s(name); string s(name);
if(!strbegin(name, "KB")) return 0; if(!strbegin(name, "KB")) return 0;
ltrim(s, "KB"); s.ltrim("KB");
unsigned id = strunsigned(s); unsigned id = strunsigned(s);
auto pos = strpos(s, "::"); auto pos = strpos(s, "::");
if(!pos) return 0; if(!pos) return 0;
@ -188,7 +188,7 @@ struct Mouse {
static uint16_t decode(const char *name) { static uint16_t decode(const char *name) {
string s(name); string s(name);
if(!strbegin(name, "MS")) return 0; if(!strbegin(name, "MS")) return 0;
ltrim(s, "MS"); s.ltrim("MS");
unsigned id = strunsigned(s); unsigned id = strunsigned(s);
auto pos = strpos(s, "::"); auto pos = strpos(s, "::");
if(!pos) return 0; if(!pos) return 0;
@ -312,7 +312,7 @@ struct Joypad {
static uint16_t decode(const char *name) { static uint16_t decode(const char *name) {
string s(name); string s(name);
if(!strbegin(name, "JP")) return 0; if(!strbegin(name, "JP")) return 0;
ltrim(s, "JP"); s.ltrim("JP");
unsigned id = strunsigned(s); unsigned id = strunsigned(s);
auto pos = strpos(s, "::"); auto pos = strpos(s, "::");
if(!pos) return 0; if(!pos) return 0;

View File

@ -23,10 +23,12 @@
#include <direct.h> #include <direct.h>
#include <shlobj.h> #include <shlobj.h>
#undef interface #undef interface
#define dllexport __declspec(dllexport)
#else #else
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
#include <sys/stat.h> #include <sys/stat.h>
#define dllexport
#endif #endif
//================== //==================
@ -76,5 +78,45 @@
#define alwaysinline inline #define alwaysinline inline
#endif #endif
//=========================
//file system functionality
//=========================
#if defined(_WIN32)
inline char* realpath(const char *filename, char *resolvedname) {
wchar_t fn[_MAX_PATH] = L"";
_wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
strcpy(resolvedname, nall::utf8_t(fn));
return resolvedname;
}
inline char* userpath(char *path) {
wchar_t fp[_MAX_PATH] = L"";
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
strcpy(path, nall::utf8_t(fp));
return path;
}
inline char* getcwd(char *path) {
wchar_t fp[_MAX_PATH] = L"";
_wgetcwd(fp, _MAX_PATH);
strcpy(path, nall::utf8_t(fp));
return path;
}
#else
//realpath() already exists
inline char* userpath(char *path) {
*path = 0;
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) strcpy(path, userinfo->pw_dir);
return path;
}
inline char *getcwd(char *path) {
return getcwd(path, PATH_MAX);
}
#endif
#endif #endif

View File

@ -1,55 +0,0 @@
# requires nall/Makefile
# imports:
# $(qtlibs) -- list of Qt components to link against
# exports the following symbols:
# $(moc) -- meta-object compiler
# $(rcc) -- resource compiler
# $(qtinc) -- includes for compiling
# $(qtlib) -- libraries for linking
ifeq ($(moc),)
moc := moc
endif
ifeq ($(rcc),)
rcc := rcc
endif
ifeq ($(platform),x)
qtinc := `pkg-config --cflags $(qtlibs)`
qtlib := `pkg-config --libs $(qtlibs)`
else ifeq ($(platform),osx)
qtinc := $(foreach lib,$(qtlibs),-I/Library/Frameworks/$(lib).framework/Versions/4/Headers)
qtlib := -L/Library/Frameworks
qtlib += $(foreach lib,$(qtlibs),-framework $(lib))
qtlib += -framework Carbon
qtlib += -framework Cocoa
qtlib += -framework OpenGL
qtlib += -framework AppKit
qtlib += -framework ApplicationServices
else ifeq ($(platform),win)
ifeq ($(qtpath),)
# find Qt install directory from PATH environment variable
qtpath := $(foreach path,$(subst ;, ,$(PATH)),$(if $(wildcard $(path)/$(moc).exe),$(path)))
qtpath := $(strip $(qtpath))
qtpath := $(subst \,/,$(qtpath))
qtpath := $(patsubst %/bin,%,$(qtpath))
endif
qtinc := -I$(qtpath)/include
qtinc += $(foreach lib,$(qtlibs),-I$(qtpath)/include/$(lib))
qtlib := -L$(qtpath)/lib
qtlib += -L$(qtpath)/plugins/imageformats
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
qtlib += -lmingw32 -lqtmain -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
qtlib += $(foreach lib,$(qtlibs),-l$(lib)4)
# optional image-file support:
# qtlib += -lqjpeg -lqmng
endif

View File

@ -1,41 +0,0 @@
#ifndef NALL_QT_CHECKACTION_HPP
#define NALL_QT_CHECKACTION_HPP
namespace nall {
class CheckAction : public QAction {
Q_OBJECT
public:
bool isChecked() const;
void setChecked(bool);
void toggleChecked();
CheckAction(const QString&, QObject*);
protected slots:
protected:
bool checked;
};
inline bool CheckAction::isChecked() const {
return checked;
}
inline void CheckAction::setChecked(bool checked_) {
checked = checked_;
if(checked) setIcon(QIcon(":/16x16/item-check-on.png"));
else setIcon(QIcon(":/16x16/item-check-off.png"));
}
inline void CheckAction::toggleChecked() {
setChecked(!isChecked());
}
inline CheckAction::CheckAction(const QString &text, QObject *parent) : QAction(text, parent) {
setChecked(false);
}
}
#endif

View File

@ -1,10 +0,0 @@
#ifndef NALL_QT_CONCEPT_HPP
#define NALL_QT_CONCEPT_HPP
#include <nall/concept.hpp>
namespace nall {
template<typename T> struct has_count<QList<T>> { enum { value = true }; };
}
#endif

View File

@ -1,392 +0,0 @@
#ifndef NALL_QT_FILEDIALOG_HPP
#define NALL_QT_FILEDIALOG_HPP
#include <nall/platform.hpp>
#include <nall/string.hpp>
#include <nall/qt/window.moc.hpp>
namespace nall {
class FileDialog;
class NewFolderDialog : public Window {
Q_OBJECT
public:
void show();
NewFolderDialog(FileDialog*);
protected slots:
void createFolderAction();
protected:
FileDialog *parent;
QVBoxLayout *layout;
QLineEdit *folderNameEdit;
QHBoxLayout *controlLayout;
QPushButton *okButton;
QPushButton *cancelButton;
};
class FileView : public QListView {
Q_OBJECT
protected:
void keyPressEvent(QKeyEvent*);
signals:
void changed(const QModelIndex&);
void browseUp();
protected slots:
void currentChanged(const QModelIndex&, const QModelIndex&);
};
class FileDialog : public Window {
Q_OBJECT
public:
void showLoad();
void showSave();
void showFolder();
void setPath(string path);
void setNameFilters(const string &filters);
FileDialog();
signals:
void changed(const string&);
void activated(const string&);
void accepted(const string&);
void rejected();
protected slots:
void fileViewChange(const QModelIndex&);
void fileViewActivate(const QModelIndex&);
void pathBoxChanged();
void filterBoxChanged();
void createNewFolder();
void browseUp();
void acceptAction();
void rejectAction();
protected:
NewFolderDialog *newFolderDialog;
QVBoxLayout *layout;
QHBoxLayout *navigationLayout;
QComboBox *pathBox;
QPushButton *newFolderButton;
QPushButton *upFolderButton;
QHBoxLayout *browseLayout;
QFileSystemModel *fileSystemModel;
FileView *fileView;
QGroupBox *previewFrame;
QLineEdit *fileNameEdit;
QHBoxLayout *controlLayout;
QComboBox *filterBox;
QPushButton *optionsButton;
QPushButton *acceptButton;
QPushButton *rejectButton;
bool lock;
void createFolderAction(const string &name);
void closeEvent(QCloseEvent*);
friend class NewFolderDialog;
};
inline void NewFolderDialog::show() {
folderNameEdit->setText("");
Window::show();
folderNameEdit->setFocus();
}
inline void NewFolderDialog::createFolderAction() {
string name = folderNameEdit->text().toUtf8().constData();
if(name == "") {
folderNameEdit->setFocus();
} else {
parent->createFolderAction(name);
close();
}
}
inline NewFolderDialog::NewFolderDialog(FileDialog *fileDialog) : parent(fileDialog) {
setMinimumWidth(240);
setWindowTitle("Create New Folder");
layout = new QVBoxLayout;
layout->setAlignment(Qt::AlignTop);
layout->setMargin(5);
layout->setSpacing(5);
setLayout(layout);
folderNameEdit = new QLineEdit;
layout->addWidget(folderNameEdit);
controlLayout = new QHBoxLayout;
controlLayout->setAlignment(Qt::AlignRight);
layout->addLayout(controlLayout);
okButton = new QPushButton("Ok");
controlLayout->addWidget(okButton);
cancelButton = new QPushButton("Cancel");
controlLayout->addWidget(cancelButton);
connect(folderNameEdit, SIGNAL(returnPressed()), this, SLOT(createFolderAction()));
connect(okButton, SIGNAL(released()), this, SLOT(createFolderAction()));
connect(cancelButton, SIGNAL(released()), this, SLOT(close()));
}
inline void FileView::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
QAbstractItemView::currentChanged(current, previous);
emit changed(current);
}
inline void FileView::keyPressEvent(QKeyEvent *event) {
//enhance consistency: force OS X to act like Windows and Linux; enter = activate item
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
emit activated(currentIndex());
return;
}
//simulate popular file manager behavior; backspace = go up one directory
if(event->key() == Qt::Key_Backspace) {
emit browseUp();
return;
}
//fallback: unrecognized keypresses get handled by the widget itself
QListView::keyPressEvent(event);
}
inline void FileDialog::showLoad() {
acceptButton->setText("Load");
fileNameEdit->hide();
filterBox->show();
show();
}
inline void FileDialog::showSave() {
acceptButton->setText("Save");
fileNameEdit->show();
filterBox->show();
show();
}
inline void FileDialog::showFolder() {
acceptButton->setText("Choose");
fileNameEdit->hide();
filterBox->hide();
setNameFilters("Folders ()");
show();
}
inline void FileDialog::fileViewChange(const QModelIndex &index) {
string path = fileSystemModel->filePath(index).toUtf8().constData();
if(path == fileSystemModel->rootPath().toUtf8().constData()) path = "";
fileNameEdit->setText(notdir(path));
emit changed(path);
}
inline void FileDialog::fileViewActivate(const QModelIndex &index) {
string path = fileSystemModel->filePath(index).toUtf8().constData();
if(fileSystemModel->isDir(index)) {
emit activated(path);
setPath(path);
} else {
emit activated(path);
close();
}
}
inline void FileDialog::pathBoxChanged() {
if(lock) return;
setPath(pathBox->currentText().toUtf8().constData());
}
inline void FileDialog::filterBoxChanged() {
if(lock) return;
string filters = filterBox->currentText().toUtf8().constData();
if(filters.length() == 0) {
fileSystemModel->setNameFilters(QStringList() << "*");
} else {
filters = substr(filters, strpos(filters, "(")());
ltrim(filters, "(");
rtrim(filters, ")");
lstring part;
part.split(" ", filters);
QStringList list;
for(unsigned i = 0; i < part.size(); i++) list << part[i];
fileSystemModel->setNameFilters(list);
}
}
inline void FileDialog::createNewFolder() {
newFolderDialog->show();
}
inline void FileDialog::browseUp() {
if(pathBox->count() > 1) pathBox->setCurrentIndex(1);
}
inline void FileDialog::setPath(string path) {
lock = true;
newFolderDialog->close();
if(QDir(path).exists()) {
newFolderButton->setEnabled(true);
} else {
newFolderButton->setEnabled(false);
path = "";
}
fileSystemModel->setRootPath(path);
fileView->setRootIndex(fileSystemModel->index(path));
fileView->setCurrentIndex(fileView->rootIndex());
fileView->setFocus();
pathBox->clear();
if(path.length() > 0) {
QDir directory(path);
while(true) {
pathBox->addItem(directory.absolutePath());
if(directory.isRoot()) break;
directory.cdUp();
}
}
pathBox->addItem("<root>");
fileNameEdit->setText("");
lock = false;
}
inline void FileDialog::setNameFilters(const string &filters) {
lock = true;
lstring list;
list.split("\n", filters);
filterBox->clear();
for(unsigned i = 0; i < list.size(); i++) {
filterBox->addItem(list[i]);
}
lock = false;
filterBoxChanged();
}
inline void FileDialog::acceptAction() {
string path = fileSystemModel->rootPath().toUtf8().constData();
path << "/" << notdir(fileNameEdit->text().toUtf8().constData());
rtrim(path, "/");
if(QDir(path).exists()) {
emit accepted(path);
setPath(path);
} else {
emit accepted(path);
close();
}
}
inline void FileDialog::rejectAction() {
emit rejected();
close();
}
inline void FileDialog::createFolderAction(const string &name) {
string path = fileSystemModel->rootPath().toUtf8().constData();
path << "/" << notdir(name);
mkdir(path, 0755);
}
inline void FileDialog::closeEvent(QCloseEvent *event) {
newFolderDialog->close();
Window::closeEvent(event);
}
inline FileDialog::FileDialog() {
newFolderDialog = new NewFolderDialog(this);
resize(640, 360);
layout = new QVBoxLayout;
layout->setMargin(5);
layout->setSpacing(5);
setLayout(layout);
navigationLayout = new QHBoxLayout;
layout->addLayout(navigationLayout);
pathBox = new QComboBox;
pathBox->setEditable(true);
pathBox->setMinimumContentsLength(16);
pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
pathBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
navigationLayout->addWidget(pathBox);
newFolderButton = new QPushButton;
newFolderButton->setIconSize(QSize(16, 16));
newFolderButton->setIcon(QIcon(":/16x16/folder-new.png"));
navigationLayout->addWidget(newFolderButton);
upFolderButton = new QPushButton;
upFolderButton->setIconSize(QSize(16, 16));
upFolderButton->setIcon(QIcon(":/16x16/go-up.png"));
navigationLayout->addWidget(upFolderButton);
browseLayout = new QHBoxLayout;
layout->addLayout(browseLayout);
fileSystemModel = new QFileSystemModel;
fileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
fileSystemModel->setNameFilterDisables(false);
fileView = new FileView;
fileView->setMinimumWidth(320);
fileView->setModel(fileSystemModel);
fileView->setIconSize(QSize(16, 16));
browseLayout->addWidget(fileView);
previewFrame = new QGroupBox;
previewFrame->hide();
browseLayout->addWidget(previewFrame);
fileNameEdit = new QLineEdit;
layout->addWidget(fileNameEdit);
controlLayout = new QHBoxLayout;
controlLayout->setAlignment(Qt::AlignRight);
layout->addLayout(controlLayout);
filterBox = new QComboBox;
filterBox->setMinimumContentsLength(16);
filterBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
filterBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
controlLayout->addWidget(filterBox);
optionsButton = new QPushButton("Options");
optionsButton->hide();
controlLayout->addWidget(optionsButton);
acceptButton = new QPushButton("Ok");
controlLayout->addWidget(acceptButton);
rejectButton = new QPushButton("Cancel");
controlLayout->addWidget(rejectButton);
lock = false;
connect(pathBox, SIGNAL(currentIndexChanged(int)), this, SLOT(pathBoxChanged()));
connect(newFolderButton, SIGNAL(released()), this, SLOT(createNewFolder()));
connect(upFolderButton, SIGNAL(released()), this, SLOT(browseUp()));
connect(fileView, SIGNAL(changed(const QModelIndex&)), this, SLOT(fileViewChange(const QModelIndex&)));
connect(fileView, SIGNAL(activated(const QModelIndex&)), this, SLOT(fileViewActivate(const QModelIndex&)));
connect(fileView, SIGNAL(browseUp()), this, SLOT(browseUp()));
connect(fileNameEdit, SIGNAL(returnPressed()), this, SLOT(acceptAction()));
connect(filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterBoxChanged()));
connect(acceptButton, SIGNAL(released()), this, SLOT(acceptAction()));
connect(rejectButton, SIGNAL(released()), this, SLOT(rejectAction()));
}
}
#endif

View File

@ -1,173 +0,0 @@
#ifndef NALL_QT_HEXEDITOR_HPP
#define NALL_QT_HEXEDITOR_HPP
#include <nall/function.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
class HexEditor : public QTextEdit {
Q_OBJECT
public:
function<uint8_t (unsigned)> reader;
function<void (unsigned, uint8_t)> writer;
void setColumns(unsigned columns);
void setRows(unsigned rows);
void setOffset(unsigned offset);
void setSize(unsigned size);
unsigned lineWidth() const;
void refresh();
HexEditor();
protected slots:
void scrolled();
protected:
QHBoxLayout *layout;
QScrollBar *scrollBar;
unsigned editorColumns;
unsigned editorRows;
unsigned editorOffset;
unsigned editorSize;
bool lock;
void keyPressEvent(QKeyEvent*);
};
inline void HexEditor::keyPressEvent(QKeyEvent *event) {
QTextCursor cursor = textCursor();
unsigned x = cursor.position() % lineWidth();
unsigned y = cursor.position() / lineWidth();
int hexCode = -1;
switch(event->key()) {
case Qt::Key_0: hexCode = 0; break;
case Qt::Key_1: hexCode = 1; break;
case Qt::Key_2: hexCode = 2; break;
case Qt::Key_3: hexCode = 3; break;
case Qt::Key_4: hexCode = 4; break;
case Qt::Key_5: hexCode = 5; break;
case Qt::Key_6: hexCode = 6; break;
case Qt::Key_7: hexCode = 7; break;
case Qt::Key_8: hexCode = 8; break;
case Qt::Key_9: hexCode = 9; break;
case Qt::Key_A: hexCode = 10; break;
case Qt::Key_B: hexCode = 11; break;
case Qt::Key_C: hexCode = 12; break;
case Qt::Key_D: hexCode = 13; break;
case Qt::Key_E: hexCode = 14; break;
case Qt::Key_F: hexCode = 15; break;
}
if(cursor.hasSelection() == false && hexCode != -1) {
bool cursorOffsetValid = (x >= 11 && ((x - 11) % 3) != 2);
if(cursorOffsetValid) {
bool nibble = (x - 11) % 3; //0 = top nibble, 1 = bottom nibble
unsigned cursorOffset = y * editorColumns + ((x - 11) / 3);
unsigned effectiveOffset = editorOffset + cursorOffset;
if(effectiveOffset >= editorSize) effectiveOffset %= editorSize;
uint8_t data = reader ? reader(effectiveOffset) : 0x00;
data &= (nibble == 0 ? 0x0f : 0xf0);
data |= (nibble == 0 ? (hexCode << 4) : (hexCode << 0));
if(writer) writer(effectiveOffset, data);
refresh();
cursor.setPosition(y * lineWidth() + x + 1); //advance cursor
setTextCursor(cursor);
}
} else {
//allow navigation keys to move cursor, but block text input
setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
QTextEdit::keyPressEvent(event);
setTextInteractionFlags(Qt::TextEditorInteraction);
}
}
inline void HexEditor::setColumns(unsigned columns) {
editorColumns = columns;
}
inline void HexEditor::setRows(unsigned rows) {
editorRows = rows;
scrollBar->setPageStep(editorRows);
}
inline void HexEditor::setOffset(unsigned offset) {
lock = true;
editorOffset = offset;
scrollBar->setSliderPosition(editorOffset / editorColumns);
lock = false;
}
inline void HexEditor::setSize(unsigned size) {
editorSize = size;
bool indivisible = (editorSize % editorColumns) != 0; //add one for incomplete row
scrollBar->setRange(0, editorSize / editorColumns + indivisible - editorRows);
}
inline unsigned HexEditor::lineWidth() const {
return 11 + 3 * editorColumns;
}
inline void HexEditor::refresh() {
string output;
char temp[256];
unsigned offset = editorOffset;
for(unsigned y = 0; y < editorRows; y++) {
if(offset >= editorSize) break;
sprintf(temp, "%.4x:%.4x", (offset >> 16) & 0xffff, (offset >> 0) & 0xffff);
output << "<font color='#808080'>" << temp << "</font>&nbsp;&nbsp;";
for(unsigned x = 0; x < editorColumns; x++) {
if(offset >= editorSize) break;
sprintf(temp, "%.2x", reader ? reader(offset) : 0x00);
offset++;
output << "<font color='" << ((x & 1) ? "#000080" : "#0000ff") << "'>" << temp << "</font>";
if(x != (editorColumns - 1)) output << "&nbsp;";
}
if(y != (editorRows - 1)) output << "<br>";
}
setHtml(output);
}
inline void HexEditor::scrolled() {
if(lock) return;
unsigned offset = scrollBar->sliderPosition();
editorOffset = offset * editorColumns;
refresh();
}
inline HexEditor::HexEditor() {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
layout = new QHBoxLayout;
layout->setAlignment(Qt::AlignRight);
layout->setMargin(0);
layout->setSpacing(0);
setLayout(layout);
scrollBar = new QScrollBar(Qt::Vertical);
scrollBar->setSingleStep(1);
layout->addWidget(scrollBar);
lock = false;
connect(scrollBar, SIGNAL(actionTriggered(int)), this, SLOT(scrolled()));
setColumns(16);
setRows(16);
setSize(0);
setOffset(0);
}
}
#endif

View File

@ -1,41 +0,0 @@
#ifndef NALL_QT_RADIOACTION_HPP
#define NALL_QT_RADIOACTION_HPP
namespace nall {
class RadioAction : public QAction {
Q_OBJECT
public:
bool isChecked() const;
void setChecked(bool);
void toggleChecked();
RadioAction(const QString&, QObject*);
protected slots:
protected:
bool checked;
};
inline bool RadioAction::isChecked() const {
return checked;
}
inline void RadioAction::setChecked(bool checked_) {
checked = checked_;
if(checked) setIcon(QIcon(":/16x16/item-radio-on.png"));
else setIcon(QIcon(":/16x16/item-radio-off.png"));
}
inline void RadioAction::toggleChecked() {
setChecked(!isChecked());
}
inline RadioAction::RadioAction(const QString &text, QObject *parent) : QAction(text, parent) {
setChecked(false);
}
}
#endif

View File

@ -1,105 +0,0 @@
#ifndef NALL_QT_WINDOW_HPP
#define NALL_QT_WINDOW_HPP
#include <nall/base64.hpp>
#include <nall/string.hpp>
namespace nall {
class Window : public QWidget {
Q_OBJECT
public:
void setGeometryString(string *geometryString);
void setCloseOnEscape(bool);
void show();
void hide();
void shrink();
Window();
protected slots:
protected:
string *geometryString;
bool closeOnEscape;
void keyReleaseEvent(QKeyEvent *event);
void closeEvent(QCloseEvent *event);
};
inline void Window::setGeometryString(string *geometryString_) {
geometryString = geometryString_;
if(geometryString && isVisible() == false) {
uint8_t *data;
unsigned length;
base64::decode(data, length, *geometryString);
QByteArray array((const char*)data, length);
delete[] data;
restoreGeometry(array);
}
}
inline void Window::setCloseOnEscape(bool value) {
closeOnEscape = value;
}
inline void Window::show() {
if(geometryString && isVisible() == false) {
uint8_t *data;
unsigned length;
base64::decode(data, length, *geometryString);
QByteArray array((const char*)data, length);
delete[] data;
restoreGeometry(array);
}
QWidget::show();
QApplication::processEvents();
activateWindow();
raise();
}
inline void Window::hide() {
if(geometryString && isVisible() == true) {
char *data;
QByteArray geometry = saveGeometry();
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
*geometryString = data;
delete[] data;
}
QWidget::hide();
}
inline void Window::shrink() {
if(isFullScreen()) return;
for(unsigned i = 0; i < 2; i++) {
resize(0, 0);
usleep(2000);
QApplication::processEvents();
}
}
inline void Window::keyReleaseEvent(QKeyEvent *event) {
if(closeOnEscape && (event->key() == Qt::Key_Escape)) close();
QWidget::keyReleaseEvent(event);
}
inline void Window::closeEvent(QCloseEvent *event) {
if(geometryString) {
char *data;
QByteArray geometry = saveGeometry();
base64::encode(data, (const uint8_t*)geometry.data(), geometry.length());
*geometryString = data;
delete[] data;
}
QWidget::closeEvent(event);
}
inline Window::Window() {
geometryString = 0;
closeOnEscape = true;
}
}
#endif

View File

@ -23,7 +23,7 @@ namespace nall {
return ::write(port, (void*)data, length); return ::write(port, (void*)data, length);
} }
bool open(const char *portname, unsigned rate) { bool open(const char *portname, unsigned rate, bool flowcontrol) {
close(); close();
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
@ -41,8 +41,13 @@ namespace nall {
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
attr.c_iflag |= (IGNBRK | IGNPAR); attr.c_iflag |= (IGNBRK | IGNPAR);
attr.c_oflag &=~ (OPOST); attr.c_oflag &=~ (OPOST);
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB); attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
attr.c_cflag |= (CS8 | CREAD | CLOCAL); attr.c_cflag |= (CS8 | CREAD);
if(flowcontrol == false) {
attr.c_cflag &= ~CRTSCTS;
} else {
attr.c_cflag |= CRTSCTS;
}
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }

View File

@ -112,6 +112,7 @@ namespace nall {
imode = Size; imode = Size;
idata = 0; idata = 0;
isize = 0; isize = 0;
icapacity = 0;
} }
serializer(unsigned capacity) { serializer(unsigned capacity) {

View File

@ -9,7 +9,7 @@ public:
inline snes_information(const uint8_t *data, unsigned size); inline snes_information(const uint8_t *data, unsigned size);
private: //private:
inline void read_header(const uint8_t *data, unsigned size); inline void read_header(const uint8_t *data, unsigned size);
inline unsigned find_header(const uint8_t *data, unsigned size); inline unsigned find_header(const uint8_t *data, unsigned size);
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
@ -558,6 +558,11 @@ void snes_information::read_header(const uint8_t *data, unsigned size) {
} }
} }
if(size < 32768) {
type = TypeUnknown;
return;
}
const unsigned index = find_header(data, size); const unsigned index = find_header(data, size);
const uint8_t mapperid = data[index + Mapper]; const uint8_t mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType]; const uint8_t rom_type = data[index + RomType];

View File

@ -2,16 +2,18 @@
#define NALL_STRING_HPP #define NALL_STRING_HPP
#include <initializer_list> #include <initializer_list>
#include <nall/platform.hpp>
#include <nall/utility.hpp> #include <nall/utility.hpp>
#include <nall/string/base.hpp> #include <nall/string/base.hpp>
#include <nall/string/bsv.hpp>
#include <nall/string/core.hpp> #include <nall/string/core.hpp>
#include <nall/string/cast.hpp> #include <nall/string/cast.hpp>
#include <nall/string/compare.hpp> #include <nall/string/compare.hpp>
#include <nall/string/convert.hpp> #include <nall/string/convert.hpp>
#include <nall/string/filename.hpp> #include <nall/string/filename.hpp>
#include <nall/string/match.hpp>
#include <nall/string/math.hpp> #include <nall/string/math.hpp>
#include <nall/string/platform.hpp>
#include <nall/string/strl.hpp> #include <nall/string/strl.hpp>
#include <nall/string/strpos.hpp> #include <nall/string/strpos.hpp>
#include <nall/string/trim.hpp> #include <nall/string/trim.hpp>
@ -19,6 +21,7 @@
#include <nall/string/split.hpp> #include <nall/string/split.hpp>
#include <nall/string/utility.hpp> #include <nall/string/utility.hpp>
#include <nall/string/variadic.hpp> #include <nall/string/variadic.hpp>
#include <nall/string/wrapper.hpp>
#include <nall/string/xml.hpp> #include <nall/string/xml.hpp>
namespace nall { namespace nall {

View File

@ -17,10 +17,43 @@ namespace nall {
class string { class string {
public: public:
inline void reserve(unsigned); inline void reserve(unsigned);
inline unsigned length() const;
inline string& assign(const char*); inline string& assign(const char*);
inline string& append(const char*); inline string& append(const char*);
inline string& append(bool);
inline string& append(signed int value);
inline string& append(unsigned int value);
inline string& append(double value);
inline bool readfile(const char*);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
inline unsigned length() const;
inline bool equals(const char*) const;
inline bool iequals(const char*) const;
inline bool wildcard(const char*) const;
inline bool iwildcard(const char*) const;
inline bool beginswith(const char*) const;
inline bool ibeginswith(const char*) const;
inline bool endswith(const char*) const;
inline bool iendswith(const char*) const;
inline string& lower();
inline string& upper();
inline string& transform(const char *before, const char *after);
template<unsigned limit = 0> inline string& ltrim(const char *key = " ");
template<unsigned limit = 0> inline string& rtrim(const char *key = " ");
template<unsigned limit = 0> inline string& trim (const char *key = " ");
inline optional<unsigned> position(const char *key) const;
inline optional<unsigned> qposition(const char *key) const;
template<typename T> inline string& operator= (T value); template<typename T> inline string& operator= (T value);
template<typename T> inline string& operator<<(T value); template<typename T> inline string& operator<<(T value);
@ -38,16 +71,11 @@ namespace nall {
inline string& operator=(const string&); inline string& operator=(const string&);
inline string& operator=(string&&); inline string& operator=(string&&);
inline string(); template<typename... Args> inline string(Args&&... args);
inline string(const char*);
inline string(const string&); inline string(const string&);
inline string(string&&); inline string(string&&);
inline ~string(); inline ~string();
inline bool readfile(const char*);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
protected: protected:
char *data; char *data;
unsigned size; unsigned size;
@ -62,9 +90,9 @@ namespace nall {
public: public:
template<typename T> inline lstring& operator<<(T value); template<typename T> inline lstring& operator<<(T value);
inline int find(const char*); inline optional<unsigned> find(const char*) const;
inline void split (const char*, const char*, unsigned = 0); template<unsigned limit = 0> inline void split (const char*, const char*);
inline void qsplit(const char*, const char*, unsigned = 0); template<unsigned limit = 0> inline void qsplit(const char*, const char*);
lstring(); lstring();
lstring(std::initializer_list<string>); lstring(std::initializer_list<string>);
@ -73,7 +101,9 @@ namespace nall {
//compare.hpp //compare.hpp
inline char chrlower(char c); inline char chrlower(char c);
inline char chrupper(char c); inline char chrupper(char c);
inline int stricmp(const char *dest, const char *src); inline int stricmp(const char *str1, const char *str2);
inline bool wildcard(const char *str, const char *pattern);
inline bool iwildcard(const char *str, const char *pattern);
inline bool strbegin (const char *str, const char *key); inline bool strbegin (const char *str, const char *key);
inline bool stribegin(const char *str, const char *key); inline bool stribegin(const char *str, const char *key);
inline bool strend (const char *str, const char *key); inline bool strend (const char *str, const char *key);
@ -89,38 +119,32 @@ namespace nall {
inline uintmax_t strbin (const char *str); inline uintmax_t strbin (const char *str);
inline double strdouble (const char *str); inline double strdouble (const char *str);
//match.hpp
inline bool match(const char *pattern, const char *str);
//math.hpp //math.hpp
inline bool strint (const char *str, int &result); inline bool strint (const char *str, int &result);
inline bool strmath(const char *str, int &result); inline bool strmath(const char *str, int &result);
//platform.hpp
inline string realpath(const char *name);
inline string userpath();
inline string currentpath();
//strl.hpp //strl.hpp
inline unsigned strlcpy(char *dest, const char *src, unsigned length); inline unsigned strlcpy(char *dest, const char *src, unsigned length);
inline unsigned strlcat(char *dest, const char *src, unsigned length); inline unsigned strlcat(char *dest, const char *src, unsigned length);
//strpos.hpp
inline optional<unsigned> strpos(const char *str, const char *key);
inline optional<unsigned> qstrpos(const char *str, const char *key);
//trim.hpp //trim.hpp
inline char* ltrim(char *str, const char *key = " "); template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
inline char* rtrim(char *str, const char *key = " "); template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
inline char* trim (char *str, const char *key = " "); template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
inline char* ltrim_once(char *str, const char *key = " ");
inline char* rtrim_once(char *str, const char *key = " ");
inline char* trim_once (char *str, const char *key = " ");
//utility.hpp //utility.hpp
inline unsigned strlcpy(string &dest, const char *src, unsigned length); inline unsigned strlcpy(string &dest, const char *src, unsigned length);
inline unsigned strlcat(string &dest, const char *src, unsigned length); inline unsigned strlcat(string &dest, const char *src, unsigned length);
inline string substr(const char *src, unsigned start = 0, unsigned length = 0); inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
inline string& strlower(string &str);
inline string& strupper(string &str);
inline string& strtr(string &dest, const char *before, const char *after);
inline string& ltrim(string &str, const char *key = " ");
inline string& rtrim(string &str, const char *key = " ");
inline string& trim (string &str, const char *key = " ");
inline string& ltrim_once(string &str, const char *key = " ");
inline string& rtrim_once(string &str, const char *key = " ");
inline string& trim_once (string &str, const char *key = " ");
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value); template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value); template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value); template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
@ -129,8 +153,7 @@ namespace nall {
inline string strdouble(double value); inline string strdouble(double value);
//variadic.hpp //variadic.hpp
template<typename... Args> inline string sprint(Args... args); template<typename... Args> inline void print(Args&&... args);
template<typename... Args> inline void print(Args... args);
}; };
#endif #endif

75
snesfilter/nall/string/bsv.hpp Executable file
View File

@ -0,0 +1,75 @@
#ifndef NALL_STRING_BSV_HPP
#define NALL_STRING_BSV_HPP
//BSV parser
//version 0.01
namespace nall {
inline string bsv_decode(const char *input) {
string output;
unsigned offset = 0;
while(*input) {
//illegal characters
if(*input == '}' ) return "";
if(*input == '\r') return "";
if(*input == '\n') return "";
//normal characters
if(*input != '{') { output[offset++] = *input++; continue; }
//entities
if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; }
if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; }
if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; }
//illegal entities
return "";
}
output[offset] = 0;
return output;
}
inline string bsv_encode(const char *input) {
string output;
unsigned offset = 0;
while(*input) {
//illegal characters
if(*input == '\r') return "";
if(*input == '\n') {
output[offset++] = '{';
output[offset++] = 'l';
output[offset++] = 'f';
output[offset++] = '}';
input++;
continue;
}
if(*input == '{') {
output[offset++] = '{';
output[offset++] = 'l';
output[offset++] = 'b';
output[offset++] = '}';
input++;
continue;
}
if(*input == '}') {
output[offset++] = '{';
output[offset++] = 'r';
output[offset++] = 'b';
output[offset++] = '}';
input++;
continue;
}
output[offset++] = *input++;
}
output[offset] = 0;
return output;
}
}
#endif

View File

@ -11,14 +11,52 @@ char chrupper(char c) {
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c; return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
} }
int stricmp(const char *dest, const char *src) { int stricmp(const char *str1, const char *str2) {
while(*dest) { while(*str1) {
if(chrlower(*dest) != chrlower(*src)) break; if(chrlower(*str1) != chrlower(*str2)) break;
dest++; str1++, str2++;
src++;
} }
return (int)chrlower(*str1) - (int)chrlower(*str2);
}
return (int)chrlower(*dest) - (int)chrlower(*src); bool wildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && *s != *p) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || *p == *s) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool iwildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
} }
bool strbegin(const char *str, const char *key) { bool strbegin(const char *str, const char *key) {

View File

@ -11,10 +11,6 @@ void string::reserve(unsigned size_) {
} }
} }
unsigned string::length() const {
return strlen(data);
}
string& string::assign(const char *s) { string& string::assign(const char *s) {
unsigned length = strlen(s); unsigned length = strlen(s);
reserve(length); reserve(length);
@ -29,6 +25,11 @@ string& string::append(const char *s) {
return *this; return *this;
} }
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
string& string::append(signed int value) { append(strsigned(value)); return *this; }
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
string& string::append(double value) { append(strdouble(value)); return *this; }
string::operator const char*() const { string::operator const char*() const {
return data; return data;
} }
@ -63,15 +64,20 @@ string& string::operator=(string &&source) {
return *this; return *this;
} }
string::string() { static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append(value);
istring(output, std::forward<Args>(args)...);
}
template<typename... Args> string::string(Args&&... args) {
size = 64; size = 64;
data = (char*)malloc(size + 1); data = (char*)malloc(size + 1);
*data = 0; *data = 0;
} istring(*this, std::forward<Args>(args)...);
string::string(const char *value) {
size = strlen(value);
data = strdup(value);
} }
string::string(const string &value) { string::string(const string &value) {
@ -86,7 +92,7 @@ string::string(string &&source) {
} }
string::~string() { string::~string() {
free(data); if(data) free(data);
} }
bool string::readfile(const char *filename) { bool string::readfile(const char *filename) {
@ -112,11 +118,11 @@ bool string::readfile(const char *filename) {
return true; return true;
} }
int lstring::find(const char *key) { optional<unsigned> lstring::find(const char *key) const {
for(unsigned i = 0; i < size(); i++) { for(unsigned i = 0; i < size(); i++) {
if(operator[](i) == key) return i; if(operator[](i) == key) return { true, i };
} }
return -1; return { false, 0 };
} }
inline lstring::lstring() { inline lstring::lstring() {

View File

@ -3,7 +3,9 @@
namespace nall { namespace nall {
// "foo/bar.c" -> "foo/", "bar.c" -> "./" // "foo/bar.c" -> "foo/"
// "foo/" -> "foo/"
// "bar.c" -> "./"
inline string dir(char const *name) { inline string dir(char const *name) {
string result = name; string result = name;
for(signed i = strlen(result); i >= 0; i--) { for(signed i = strlen(result); i >= 0; i--) {

View File

@ -1,76 +0,0 @@
#ifndef NALL_STRING_MATCH_HPP
#define NALL_STRING_MATCH_HPP
namespace nall {
bool match(const char *p, const char *s) {
const char *p_ = 0, *s_ = 0;
for(;;) {
if(!*s) {
while(*p == '*') p++;
return !*p;
}
//wildcard match
if(*p == '*') {
p_ = p++, s_ = s;
continue;
}
//any match
if(*p == '?') {
p++, s++;
continue;
}
//ranged match
if(*p == '{') {
#define pattern(name_, rule_) \
if(strbegin(p, name_)) { \
if(rule_) { \
p += sizeof(name_) - 1, s++; \
continue; \
} \
goto failure; \
}
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
pattern("{binary}", (*s == '0' || *s == '1'))
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
pattern("{numeric}", (*s >= '0' && *s <= '9'))
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
#undef pattern
goto failure;
}
//reserved character match
if(*p == '\\') {
p++;
//fallthrough
}
//literal match
if(*p == *s) {
p++, *s++;
continue;
}
//attempt wildcard rematch
failure:
if(p_) {
p = p_, s = s_ + 1;
continue;
}
return false;
}
}
}
#endif

View File

@ -0,0 +1,41 @@
#ifndef NALL_STRING_PLATFORM_HPP
#define NALL_STRING_PLATFORM_HPP
namespace nall {
string realpath(const char *name) {
char path[PATH_MAX];
if(::realpath(name, path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
string userpath() {
char path[PATH_MAX];
if(::userpath(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
string currentpath() {
char path[PATH_MAX];
if(::getcwd(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
}
#endif

View File

@ -3,7 +3,8 @@
namespace nall { namespace nall {
void lstring::split(const char *key, const char *src, unsigned limit) { template<unsigned Limit> void lstring::split(const char *key, const char *src) {
unsigned limit = Limit;
reset(); reset();
int ssl = strlen(src), ksl = strlen(key); int ssl = strlen(src), ksl = strlen(key);
@ -21,7 +22,8 @@ void lstring::split(const char *key, const char *src, unsigned limit) {
operator[](split_count++) = src + lp; operator[](split_count++) = src + lp;
} }
void lstring::qsplit(const char *key, const char *src, unsigned limit) { template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
unsigned limit = Limit;
reset(); reset();
int ssl = strlen(src), ksl = strlen(key); int ssl = strlen(src), ksl = strlen(key);

View File

@ -7,7 +7,7 @@
namespace nall { namespace nall {
optional<unsigned> inline strpos(const char *str, const char *key) { optional<unsigned> strpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key); unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 }; if(ksl > ssl) return { false, 0 };
@ -18,7 +18,7 @@ optional<unsigned> inline strpos(const char *str, const char *key) {
return { false, 0 }; return { false, 0 };
} }
optional<unsigned> inline qstrpos(const char *str, const char *key) { optional<unsigned> qstrpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key); unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 }; if(ksl > ssl) return { false, 0 };

View File

@ -3,7 +3,9 @@
namespace nall { namespace nall {
char* ltrim(char *str, const char *key) { //limit defaults to zero, which will underflow on first compare; equivalent to no limit
template<unsigned Limit> char* ltrim(char *str, const char *key) {
unsigned limit = Limit;
if(!key || !*key) return str; if(!key || !*key) return str;
while(strbegin(str, key)) { while(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key); char *dest = str, *src = str + strlen(key);
@ -12,41 +14,23 @@ char* ltrim(char *str, const char *key) {
if(!*dest) break; if(!*dest) break;
dest++; dest++;
} }
if(--limit == 0) break;
} }
return str; return str;
} }
char* rtrim(char *str, const char *key) { template<unsigned Limit> char* rtrim(char *str, const char *key) {
unsigned limit = Limit;
if(!key || !*key) return str; if(!key || !*key) return str;
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0; while(strend(str, key)) {
return str; str[strlen(str) - strlen(key)] = 0;
} if(--limit == 0) break;
char* trim(char *str, const char *key) {
return ltrim(rtrim(str, key), key);
}
char* ltrim_once(char *str, const char *key) {
if(!key || !*key) return str;
if(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
} }
return str; return str;
} }
char* rtrim_once(char *str, const char *key) { template<unsigned limit> char* trim(char *str, const char *key) {
if(!key || !*key) return str; return ltrim<limit>(rtrim<limit>(str, key), key);
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
return str;
}
char* trim_once(char *str, const char *key) {
return ltrim_once(rtrim_once(str, key), key);
} }
} }

View File

@ -25,18 +25,6 @@ string substr(const char *src, unsigned start, unsigned length) {
return dest; return dest;
} }
/* very simplistic wrappers to return string& instead of char* type */
string& strlower(string &str) { strlower(str()); return str; }
string& strupper(string &str) { strupper(str()); return str; }
string& strtr(string &dest, const char *before, const char *after) { strtr(dest(), before, after); return dest; }
string& ltrim(string &str, const char *key) { ltrim(str(), key); return str; }
string& rtrim(string &str, const char *key) { rtrim(str(), key); return str; }
string& trim (string &str, const char *key) { trim (str(), key); return str; }
string& ltrim_once(string &str, const char *key) { ltrim_once(str(), key); return str; }
string& rtrim_once(string &str, const char *key) { rtrim_once(str(), key); return str; }
string& trim_once (string &str, const char *key) { trim_once (str(), key); return str; }
/* arithmetic <> string */ /* arithmetic <> string */
template<unsigned length, char padding> string strhex(uintmax_t value) { template<unsigned length, char padding> string strhex(uintmax_t value) {

View File

@ -3,23 +3,8 @@
namespace nall { namespace nall {
static void isprint(string &output) { template<typename... Args> inline void print(Args&&... args) {
} printf("%s", (const char*)string(std::forward<Args>(args)...));
template<typename T, typename... Args>
static void isprint(string &output, T value, Args... args) {
output << to_string<T>(value);
isprint(output, args...);
}
template<typename... Args> inline string sprint(Args... args) {
string output;
isprint(output, args...);
return output;
}
template<typename... Args> inline void print(Args... args) {
printf("%s", (const char*)sprint(args...));
} }
} }

View File

@ -0,0 +1,33 @@
#ifndef NALL_STRING_WRAPPER_HPP
#define NALL_STRING_WRAPPER_HPP
namespace nall {
unsigned string::length() const { return strlen(data); }
bool string::equals(const char *str) const { return !strcmp(data, str); }
bool string::iequals(const char *str) const { return !stricmp(data, str); }
bool string::wildcard(const char *str) const { return nall::wildcard(data, str); }
bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); }
bool string::beginswith(const char *str) const { return strbegin(data, str); }
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
bool string::endswith(const char *str) const { return strend(data, str); }
bool string::iendswith(const char *str) const { return striend(data, str); }
string& string::lower() { nall::strlower(data); return *this; }
string& string::upper() { nall::strupper(data); return *this; }
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
template<unsigned limit> string& string::ltrim(const char *key) { nall::ltrim<limit>(data, key); return *this; }
template<unsigned limit> string& string::rtrim(const char *key) { nall::rtrim<limit>(data, key); return *this; }
template<unsigned limit> string& string::trim (const char *key) { nall::trim <limit>(data, key); return *this; }
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
}
#endif

View File

@ -75,11 +75,12 @@ inline string xml_element::parse() const {
if(strbegin(source, "<![CDATA[")) { if(strbegin(source, "<![CDATA[")) {
if(auto pos = strpos(source, "]]>")) { if(auto pos = strpos(source, "]]>")) {
string cdata = substr(source, 9, pos() - 9); if(pos() - 9 > 0) {
data << cdata; string cdata = substr(source, 9, pos() - 9);
offset += strlen(cdata); data << cdata;
offset += strlen(cdata);
source += offset + 3; }
source += 9 + offset + 3;
continue; continue;
} else { } else {
return ""; return "";
@ -122,7 +123,7 @@ inline bool xml_element::parse_head(string data) {
while(qstrpos(data, " ")) data.qreplace(" ", " "); while(qstrpos(data, " ")) data.qreplace(" ", " ");
data.qreplace(" =", "="); data.qreplace(" =", "=");
data.qreplace("= ", "="); data.qreplace("= ", "=");
rtrim(data); data.rtrim();
lstring part; lstring part;
part.qsplit(" ", data); part.qsplit(" ", data);
@ -138,8 +139,8 @@ inline bool xml_element::parse_head(string data) {
xml_attribute attr; xml_attribute attr;
attr.name = side[0]; attr.name = side[0];
attr.content = side[1]; attr.content = side[1];
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) trim_once(attr.content, "\""); if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) trim_once(attr.content, "'"); else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
else throw "..."; else throw "...";
attribute.append(attr); attribute.append(attr);
} }
@ -185,10 +186,10 @@ inline bool xml_element::parse_body(const char *&data) {
if(strend(tag, "?") == true) { if(strend(tag, "?") == true) {
self_terminating = true; self_terminating = true;
rtrim_once(tag, "?"); tag.rtrim<1>("?");
} else if(strend(tag, "/") == true) { } else if(strend(tag, "/") == true) {
self_terminating = true; self_terminating = true;
rtrim_once(tag, "/"); tag.rtrim<1>("/");
} }
parse_head(tag); parse_head(tag);
@ -213,7 +214,7 @@ inline bool xml_element::parse_body(const char *&data) {
tag.replace("\r", " "); tag.replace("\r", " ");
tag.replace("\n", " "); tag.replace("\n", " ");
while(strpos(tag, " ")) tag.replace(" ", " "); while(strpos(tag, " ")) tag.replace(" ", " ");
rtrim(tag); tag.rtrim();
if(name != tag) throw "..."; if(name != tag) throw "...";
return true; return true;

View File

@ -1,190 +1,223 @@
#ifndef NALL_UPS_HPP #ifndef NALL_UPS_HPP
#define NALL_UPS_HPP #define NALL_UPS_HPP
#include <stdio.h>
#include <nall/algorithm.hpp>
#include <nall/crc32.hpp> #include <nall/crc32.hpp>
#include <nall/file.hpp> #include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
namespace nall { namespace nall {
class ups {
public:
enum result {
ok,
patch_unreadable,
patch_unwritable,
patch_invalid,
input_invalid,
output_invalid,
patch_crc32_invalid,
input_crc32_invalid,
output_crc32_invalid,
};
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) { struct ups {
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable; enum class result : unsigned {
unknown,
success,
patch_unwritable,
patch_invalid,
source_invalid,
target_invalid,
target_too_small,
patch_checksum_invalid,
source_checksum_invalid,
target_checksum_invalid,
};
crc32 = ~0; function<void (unsigned offset, unsigned length)> progress;
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
//header result create(
write('U'); const uint8_t *sourcedata, unsigned sourcelength,
write('P'); const uint8_t *targetdata, unsigned targetlength,
write('S'); const char *patchfilename
write('1'); ) {
encptr(x_size); source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata;
encptr(y_size); source_length = sourcelength, target_length = targetlength;
source_offset = target_offset = 0;
source_checksum = target_checksum = patch_checksum = ~0;
//body if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable;
unsigned max_size = max(x_size, y_size);
unsigned relative = 0;
for(unsigned i = 0; i < max_size;) {
uint8_t x = i < x_size ? x_data[i] : 0x00;
uint8_t y = i < y_size ? y_data[i] : 0x00;
if(x == y) { patch_write('U');
i++; patch_write('P');
continue; patch_write('S');
} patch_write('1');
encode(source_length);
encode(target_length);
encptr(i++ - relative); unsigned output_length = source_length > target_length ? source_length : target_length;
write(x ^ y); unsigned relative = 0;
for(unsigned offset = 0; offset < output_length;) {
uint8_t x = source_read();
uint8_t y = target_read();
while(true) { if(x == y) {
if(i >= max_size) { offset++;
write(0x00); continue;
break;
}
x = i < x_size ? x_data[i] : 0x00;
y = i < y_size ? y_data[i] : 0x00;
i++;
write(x ^ y);
if(x == y) break;
}
relative = i;
} }
//footer encode(offset++ - relative);
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3)); patch_write(x ^ y);
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
uint32_t p_crc32 = ~crc32;
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
fp.close();
return ok;
}
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
if(p_size < 18) return patch_invalid;
p_buffer = p_data;
crc32 = ~0;
//header
if(read() != 'U') return patch_invalid;
if(read() != 'P') return patch_invalid;
if(read() != 'S') return patch_invalid;
if(read() != '1') return patch_invalid;
unsigned px_size = decptr();
unsigned py_size = decptr();
//mirror
if(x_size != px_size && x_size != py_size) return input_invalid;
y_size = (x_size == px_size) ? py_size : px_size;
y_data = new uint8_t[y_size]();
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
//body
unsigned relative = 0;
while(p_buffer < p_data + p_size - 12) {
relative += decptr();
while(true) {
uint8_t x = read();
if(x && relative < y_size) {
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
y_data[relative] = x ^ y;
}
relative++;
if(!x) break;
}
}
//footer
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
uint32_t p_crc32 = ~crc32;
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
if(px_size != py_size) {
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
} else {
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
}
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
return ok;
}
private:
file fp;
uint32_t crc32;
const uint8_t *p_buffer;
uint8_t read() {
uint8_t n = *p_buffer++;
crc32 = crc32_adjust(crc32, n);
return n;
}
void write(uint8_t n) {
fp.write(n);
crc32 = crc32_adjust(crc32, n);
}
void encptr(uint64_t offset) {
while(true) { while(true) {
uint64_t x = offset & 0x7f; if(offset >= output_length) {
offset >>= 7; patch_write(0x00);
if(offset == 0) {
write(0x80 | x);
break; break;
} }
write(x);
offset--; x = source_read();
y = target_read();
offset++;
patch_write(x ^ y);
if(x == y) break;
} }
relative = offset;
} }
uint64_t decptr() { source_checksum = ~source_checksum;
uint64_t offset = 0, shift = 1; target_checksum = ~target_checksum;
for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8));
for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8));
uint32_t patch_result_checksum = ~patch_checksum;
for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8));
patch_file.close();
return result::success;
}
result apply(
const uint8_t *patchdata, unsigned patchlength,
const uint8_t *sourcedata, unsigned sourcelength,
uint8_t *targetdata, unsigned &targetlength
) {
patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata;
patch_length = patchlength, source_length = sourcelength, target_length = targetlength;
patch_offset = source_offset = target_offset = 0;
patch_checksum = source_checksum = target_checksum = ~0;
if(patch_length < 18) return result::patch_invalid;
if(patch_read() != 'U') return result::patch_invalid;
if(patch_read() != 'P') return result::patch_invalid;
if(patch_read() != 'S') return result::patch_invalid;
if(patch_read() != '1') return result::patch_invalid;
unsigned source_read_length = decode();
unsigned target_read_length = decode();
if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid;
targetlength = (source_length == source_read_length ? target_read_length : source_read_length);
if(target_length < targetlength) return result::target_too_small;
target_length = targetlength;
while(patch_offset < patch_length - 12) {
unsigned length = decode();
while(length--) target_write(source_read());
while(true) { while(true) {
uint8_t x = read(); uint8_t patch_xor = patch_read();
offset += (x & 0x7f) * shift; target_write(patch_xor ^ source_read());
if(x & 0x80) break; if(patch_xor == 0) break;
shift <<= 7;
offset += shift;
} }
return offset;
} }
}; while(source_offset < source_length) target_write(source_read());
while(target_offset < target_length) target_write(source_read());
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8);
uint32_t patch_result_checksum = ~patch_checksum;
source_checksum = ~source_checksum;
target_checksum = ~target_checksum;
for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8);
if(patch_result_checksum != patch_read_checksum) return result::patch_invalid;
if(source_checksum == source_read_checksum && source_length == source_read_length) {
if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success;
return result::target_invalid;
} else if(source_checksum == target_read_checksum && source_length == target_read_length) {
if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success;
return result::target_invalid;
} else {
return result::source_invalid;
}
}
private:
uint8_t *patch_data, *source_data, *target_data;
unsigned patch_length, source_length, target_length;
unsigned patch_offset, source_offset, target_offset;
unsigned patch_checksum, source_checksum, target_checksum;
file patch_file;
uint8_t patch_read() {
if(patch_offset < patch_length) {
uint8_t n = patch_data[patch_offset++];
patch_checksum = crc32_adjust(patch_checksum, n);
return n;
}
return 0x00;
}
uint8_t source_read() {
if(source_offset < source_length) {
uint8_t n = source_data[source_offset++];
source_checksum = crc32_adjust(source_checksum, n);
return n;
}
return 0x00;
}
uint8_t target_read() {
uint8_t result = 0x00;
if(target_offset < target_length) {
result = target_data[target_offset];
target_checksum = crc32_adjust(target_checksum, result);
}
if(((target_offset++ & 255) == 0) && progress) {
progress(target_offset, source_length > target_length ? source_length : target_length);
}
return result;
}
void patch_write(uint8_t n) {
patch_file.write(n);
patch_checksum = crc32_adjust(patch_checksum, n);
}
void target_write(uint8_t n) {
if(target_offset < target_length) {
target_data[target_offset] = n;
target_checksum = crc32_adjust(target_checksum, n);
}
if(((target_offset++ & 255) == 0) && progress) {
progress(target_offset, source_length > target_length ? source_length : target_length);
}
}
void encode(uint64_t offset) {
while(true) {
uint64_t x = offset & 0x7f;
offset >>= 7;
if(offset == 0) {
patch_write(0x80 | x);
break;
}
patch_write(x);
offset--;
}
}
uint64_t decode() {
uint64_t offset = 0, shift = 1;
while(true) {
uint8_t x = patch_read();
offset += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
offset += shift;
}
return offset;
}
};
} }
#endif #endif

View File

@ -6,9 +6,11 @@
#if defined(_WIN32) #if defined(_WIN32)
#undef UNICODE
#undef _WIN32_WINNT #undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#undef NOMINMAX #undef NOMINMAX
#define UNICODE
#define _WIN32_WINNT 0x0501
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>
#undef interface #undef interface
@ -62,9 +64,21 @@ namespace nall {
delete[] buffer; delete[] buffer;
} }
utf8_t(const utf8_t&) = delete;
utf8_t& operator=(const utf8_t&) = delete;
private: private:
char *buffer; char *buffer;
}; };
inline void utf8_args(int &argc, char **&argv) {
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
argv = new char*[argc];
for(unsigned i = 0; i < argc; i++) {
argv[i] = new char[_MAX_PATH];
strcpy(argv[i], nall::utf8_t(wargv[i]));
}
}
} }
#endif //if defined(_WIN32) #endif //if defined(_WIN32)

View File

@ -1,9 +1,9 @@
#ifndef NALL_VARINT_HPP #ifndef NALL_VARINT_HPP
#define NALL_VARINT_HPP #define NALL_VARINT_HPP
#include <type_traits>
#include <nall/bit.hpp> #include <nall/bit.hpp>
#include <nall/static.hpp> #include <nall/static.hpp>
#include <nall/traits.hpp>
namespace nall { namespace nall {
template<unsigned bits> class uint_t { template<unsigned bits> class uint_t {
@ -22,7 +22,7 @@ namespace nall {
>::type >::type
>::type >::type
>::type T; >::type T;
static_assert<!is_void<T>::value> uint_assert; static_assert(!std::is_same<T, void>::value, "");
T data; T data;
public: public:
@ -63,7 +63,7 @@ namespace nall {
>::type >::type
>::type >::type
>::type T; >::type T;
static_assert<!is_void<T>::value> int_assert; static_assert(!std::is_same<T, void>::value, "");
T data; T data;
public: public:

View File

@ -0,0 +1,63 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
uint32_t *colortable;
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
struct snes_ntsc_t *ntsc;
snes_ntsc_setup_t setup;
int burst;
int burst_toggle;
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
setup = snes_ntsc_composite;
setup.merge_fields = 1;
snes_ntsc_init(ntsc, &setup);
burst = 0;
burst_toggle = (setup.merge_fields ? 0 : 1);
}
void terminate() {
if(ntsc) free(ntsc);
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
width = SNES_NTSC_OUT_WIDTH(256);
height = height;
}
dllexport void filter_render(
uint32_t *colortable_, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
if(!ntsc) return;
colortable = colortable_;
pitch >>= 1;
outpitch >>= 2;
if(width <= 256) {
snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2);
}
burst ^= burst_toggle;
}

63
snesfilter/ntsc/ntsc-rf.cpp Executable file
View File

@ -0,0 +1,63 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
uint32_t *colortable;
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
struct snes_ntsc_t *ntsc;
snes_ntsc_setup_t setup;
int burst;
int burst_toggle;
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
setup = snes_ntsc_composite;
setup.merge_fields = 0;
snes_ntsc_init(ntsc, &setup);
burst = 0;
burst_toggle = (setup.merge_fields ? 0 : 1);
}
void terminate() {
if(ntsc) free(ntsc);
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
width = SNES_NTSC_OUT_WIDTH(256);
height = height;
}
dllexport void filter_render(
uint32_t *colortable_, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
if(!ntsc) return;
colortable = colortable_;
pitch >>= 1;
outpitch >>= 2;
if(width <= 256) {
snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2);
}
burst ^= burst_toggle;
}

63
snesfilter/ntsc/ntsc-rgb.cpp Executable file
View File

@ -0,0 +1,63 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
uint32_t *colortable;
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
struct snes_ntsc_t *ntsc;
snes_ntsc_setup_t setup;
int burst;
int burst_toggle;
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
setup = snes_ntsc_rgb;
setup.merge_fields = 1;
snes_ntsc_init(ntsc, &setup);
burst = 0;
burst_toggle = (setup.merge_fields ? 0 : 1);
}
void terminate() {
if(ntsc) free(ntsc);
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
width = SNES_NTSC_OUT_WIDTH(256);
height = height;
}
dllexport void filter_render(
uint32_t *colortable_, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
if(!ntsc) return;
colortable = colortable_;
pitch >>= 1;
outpitch >>= 2;
if(width <= 256) {
snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2);
}
burst ^= burst_toggle;
}

63
snesfilter/ntsc/ntsc-svideo.cpp Executable file
View File

@ -0,0 +1,63 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
uint32_t *colortable;
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
struct snes_ntsc_t *ntsc;
snes_ntsc_setup_t setup;
int burst;
int burst_toggle;
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
setup = snes_ntsc_svideo;
setup.merge_fields = 1;
snes_ntsc_init(ntsc, &setup);
burst = 0;
burst_toggle = (setup.merge_fields ? 0 : 1);
}
void terminate() {
if(ntsc) free(ntsc);
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
width = SNES_NTSC_OUT_WIDTH(256);
height = height;
}
dllexport void filter_render(
uint32_t *colortable_, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
if(!ntsc) return;
colortable = colortable_;
pitch >>= 1;
outpitch >>= 2;
if(width <= 256) {
snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2);
}
burst ^= burst_toggle;
}

View File

@ -1,380 +0,0 @@
#include "snes_ntsc/snes_ntsc.h"
#include "snes_ntsc/snes_ntsc.c"
#include "ntsc.moc.hpp"
#include "ntsc.moc"
void NTSCFilter::bind(configuration &config) {
config.attach(hue = 0.0, "snesfilter.ntsc.hue");
config.attach(saturation = 0.0, "snesfilter.ntsc.saturation");
config.attach(contrast = 0.0, "snesfilter.ntsc.contrast");
config.attach(brightness = 0.0, "snesfilter.ntsc.brightness");
config.attach(sharpness = 0.0, "snesfilter.ntsc.sharpness");
config.attach(gamma = 0.0, "snesfilter.ntsc.gamma");
config.attach(resolution = 0.0, "snesfilter.ntsc.resolution");
config.attach(artifacts = 0.0, "snesfilter.ntsc.artifacts");
config.attach(fringing = 0.0, "snesfilter.ntsc.fringing");
config.attach(bleed = 0.0, "snesfilter.ntsc.bleed");
config.attach(mergeFields = true, "snesfilter.ntsc.mergeFields");
}
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = SNES_NTSC_OUT_WIDTH(256);
outheight = height;
}
void NTSCFilter::render(
uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
if(!ntsc) return;
pitch >>= 1;
outpitch >>= 2;
if(width <= 256) {
snes_ntsc_blit (ntsc, input, pitch, burst, width, height, output, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, input, pitch, burst, width, height, output, outpitch << 2);
}
burst ^= burst_toggle;
}
QWidget* NTSCFilter::settings() {
if(!widget) {
widget = new QWidget;
widget->setWindowTitle("NTSC Filter Configuration");
layout = new QVBoxLayout;
layout->setAlignment(Qt::AlignTop);
widget->setLayout(layout);
gridLayout = new QGridLayout;
layout->addLayout(gridLayout);
basicSettings = new QLabel("<b>Basic settings:</b>");
gridLayout->addWidget(basicSettings, 0, 0, 1, 3);
hueLabel = new QLabel("Hue:");
gridLayout->addWidget(hueLabel, 1, 0);
hueValue = new QLabel;
hueValue->setMinimumWidth(hueValue->fontMetrics().width("-100.0"));
hueValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(hueValue, 1, 1);
hueSlider = new QSlider(Qt::Horizontal);
hueSlider->setMinimum(-100);
hueSlider->setMaximum(+100);
gridLayout->addWidget(hueSlider, 1, 2);
saturationLabel = new QLabel("Saturation:");
gridLayout->addWidget(saturationLabel, 2, 0);
saturationValue = new QLabel;
saturationValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(saturationValue, 2, 1);
saturationSlider = new QSlider(Qt::Horizontal);
saturationSlider->setMinimum(-100);
saturationSlider->setMaximum(+100);
gridLayout->addWidget(saturationSlider, 2, 2);
contrastLabel = new QLabel("Contrast:");
gridLayout->addWidget(contrastLabel, 3, 0);
contrastValue = new QLabel;
contrastValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(contrastValue, 3, 1);
contrastSlider = new QSlider(Qt::Horizontal);
contrastSlider->setMinimum(-100);
contrastSlider->setMaximum(+100);
gridLayout->addWidget(contrastSlider, 3, 2);
brightnessLabel = new QLabel("Brightness:");
gridLayout->addWidget(brightnessLabel, 4, 0);
brightnessValue = new QLabel;
brightnessValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(brightnessValue, 4, 1);
brightnessSlider = new QSlider(Qt::Horizontal);
brightnessSlider->setMinimum(-100);
brightnessSlider->setMaximum(+100);
gridLayout->addWidget(brightnessSlider, 4, 2);
sharpnessLabel = new QLabel("Sharpness:");
gridLayout->addWidget(sharpnessLabel, 5, 0);
sharpnessValue = new QLabel;
sharpnessValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(sharpnessValue, 5, 1);
sharpnessSlider = new QSlider(Qt::Horizontal);
sharpnessSlider->setMinimum(-100);
sharpnessSlider->setMaximum(+100);
gridLayout->addWidget(sharpnessSlider, 5, 2);
advancedSettings = new QLabel("<b>Advanced settings:</b>");
gridLayout->addWidget(advancedSettings, 6, 0, 1, 3);
gammaLabel = new QLabel("Gamma:");
gridLayout->addWidget(gammaLabel, 7, 0);
gammaValue = new QLabel;
gammaValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(gammaValue, 7, 1);
gammaSlider = new QSlider(Qt::Horizontal);
gammaSlider->setMinimum(-100);
gammaSlider->setMaximum(+100);
gridLayout->addWidget(gammaSlider, 7, 2);
resolutionLabel = new QLabel("Resolution:");
gridLayout->addWidget(resolutionLabel, 8, 0);
resolutionValue = new QLabel;
resolutionValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(resolutionValue, 8, 1);
resolutionSlider = new QSlider(Qt::Horizontal);
resolutionSlider->setMinimum(-100);
resolutionSlider->setMaximum(+100);
gridLayout->addWidget(resolutionSlider, 8, 2);
artifactsLabel = new QLabel("Artifacts:");
gridLayout->addWidget(artifactsLabel, 9, 0);
artifactsValue = new QLabel;
artifactsValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(artifactsValue, 9, 1);
artifactsSlider = new QSlider(Qt::Horizontal);
artifactsSlider->setMinimum(-100);
artifactsSlider->setMaximum(+100);
gridLayout->addWidget(artifactsSlider, 9, 2);
fringingLabel = new QLabel("Fringing:");
gridLayout->addWidget(fringingLabel, 10, 0);
fringingValue = new QLabel;
fringingValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(fringingValue, 10, 1);
fringingSlider = new QSlider(Qt::Horizontal);
fringingSlider->setMinimum(-100);
fringingSlider->setMaximum(+100);
gridLayout->addWidget(fringingSlider, 10, 2);
bleedLabel = new QLabel("Color bleed:");
gridLayout->addWidget(bleedLabel, 11, 0);
bleedValue = new QLabel;
bleedValue->setAlignment(Qt::AlignHCenter);
gridLayout->addWidget(bleedValue, 11, 1);
bleedSlider = new QSlider(Qt::Horizontal);
bleedSlider->setMinimum(-100);
bleedSlider->setMaximum(+100);
gridLayout->addWidget(bleedSlider, 11, 2);
mergeFieldsBox = new QCheckBox("Merge even and odd fields to reduce flicker");
gridLayout->addWidget(mergeFieldsBox, 12, 0, 1, 3);
presets = new QLabel("<b>Presets:</b>");
gridLayout->addWidget(presets, 13, 0, 1, 3);
controlLayout = new QHBoxLayout;
layout->addLayout(controlLayout);
rfPreset = new QPushButton("RF");
controlLayout->addWidget(rfPreset);
compositePreset = new QPushButton("Composite");
controlLayout->addWidget(compositePreset);
svideoPreset = new QPushButton("S-Video");
controlLayout->addWidget(svideoPreset);
rgbPreset = new QPushButton("RGB");
controlLayout->addWidget(rgbPreset);
monoPreset = new QPushButton("Monochrome");
controlLayout->addWidget(monoPreset);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
spacer->setMinimumWidth(50);
controlLayout->addWidget(spacer);
ok = new QPushButton("Ok");
controlLayout->addWidget(ok);
blockSignals = true;
loadSettingsFromConfig();
syncUiToSettings();
initialize();
connect(hueSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(contrastSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(sharpnessSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(gammaSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(resolutionSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(artifactsSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(fringingSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(bleedSlider, SIGNAL(valueChanged(int)), this, SLOT(syncSettingsToUi()));
connect(mergeFieldsBox, SIGNAL(stateChanged(int)), this, SLOT(syncSettingsToUi()));
connect(rfPreset, SIGNAL(released()), this, SLOT(setRfPreset()));
connect(compositePreset, SIGNAL(released()), this, SLOT(setCompositePreset()));
connect(svideoPreset, SIGNAL(released()), this, SLOT(setSvideoPreset()));
connect(rgbPreset, SIGNAL(released()), this, SLOT(setRgbPreset()));
connect(monoPreset, SIGNAL(released()), this, SLOT(setMonoPreset()));
connect(ok, SIGNAL(released()), widget, SLOT(hide()));
blockSignals = false;
}
return widget;
}
void NTSCFilter::initialize() {
burst = 0;
burst_toggle = (setup.merge_fields ? 0 : 1); //don't toggle burst when fields are merged
snes_ntsc_init(ntsc, &setup);
}
void NTSCFilter::loadSettingsFromConfig() {
setup.hue = hue;
setup.saturation = saturation;
setup.contrast = contrast;
setup.brightness = brightness;
setup.sharpness = sharpness;
setup.gamma = gamma;
setup.resolution = resolution;
setup.artifacts = artifacts;
setup.fringing = fringing;
setup.bleed = bleed;
setup.merge_fields = mergeFields;
}
void NTSCFilter::syncUiToSettings() {
blockSignals = true;
hue = setup.hue;
saturation = setup.saturation;
contrast = setup.contrast;
brightness = setup.brightness;
sharpness = setup.sharpness;
gamma = setup.gamma;
resolution = setup.resolution;
artifacts = setup.artifacts;
fringing = setup.fringing;
bleed = setup.bleed;
mergeFields = setup.merge_fields;
hueValue->setText(string() << hue);
hueSlider->setSliderPosition(hue * 100);
saturationValue->setText(string() << saturation);
saturationSlider->setSliderPosition(saturation * 100);
contrastValue->setText(string() << contrast);
contrastSlider->setSliderPosition(contrast * 100);
brightnessValue->setText(string() << brightness);
brightnessSlider->setSliderPosition(brightness * 100);
sharpnessValue->setText(string() << sharpness);
sharpnessSlider->setSliderPosition(sharpness * 100);
gammaValue->setText(string() << gamma);
gammaSlider->setSliderPosition(gamma * 100);
resolutionValue->setText(string() << resolution);
resolutionSlider->setSliderPosition(resolution * 100);
artifactsValue->setText(string() << artifacts);
artifactsSlider->setSliderPosition(artifacts * 100);
fringingValue->setText(string() << fringing);
fringingSlider->setSliderPosition(fringing * 100);
bleedValue->setText(string() << bleed);
bleedSlider->setSliderPosition(bleed * 100);
mergeFieldsBox->setChecked(mergeFields);
blockSignals = false;
}
void NTSCFilter::syncSettingsToUi() {
if(blockSignals) return;
hue = hueSlider->sliderPosition() / 100.0;
saturation = saturationSlider->sliderPosition() / 100.0;
contrast = contrastSlider->sliderPosition() / 100.0;
brightness = brightnessSlider->sliderPosition() / 100.0;
sharpness = sharpnessSlider->sliderPosition() / 100.0;
gamma = gammaSlider->sliderPosition() / 100.0;
resolution = resolutionSlider->sliderPosition() / 100.0;
artifacts = artifactsSlider->sliderPosition() / 100.0;
fringing = fringingSlider->sliderPosition() / 100.0;
bleed = bleedSlider->sliderPosition() / 100.0;
mergeFields = mergeFieldsBox->isChecked();
loadSettingsFromConfig();
syncUiToSettings();
initialize();
}
void NTSCFilter::setRfPreset() {
static snes_ntsc_setup_t defaults;
setup = defaults;
syncUiToSettings();
initialize();
}
void NTSCFilter::setCompositePreset() {
setup = snes_ntsc_composite;
syncUiToSettings();
initialize();
}
void NTSCFilter::setSvideoPreset() {
setup = snes_ntsc_svideo;
syncUiToSettings();
initialize();
}
void NTSCFilter::setRgbPreset() {
setup = snes_ntsc_rgb;
syncUiToSettings();
initialize();
}
void NTSCFilter::setMonoPreset() {
setup = snes_ntsc_monochrome;
syncUiToSettings();
initialize();
}
NTSCFilter::NTSCFilter() : widget(0) {
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
static snes_ntsc_setup_t defaults;
setup = defaults;
initialize();
}
NTSCFilter::~NTSCFilter() {
if(ntsc) free(ntsc);
}

View File

@ -1,91 +0,0 @@
class NTSCFilter : public QObject {
Q_OBJECT
public:
void bind(configuration&);
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
QWidget* settings();
NTSCFilter();
~NTSCFilter();
private:
void initialize();
void loadSettingsFromConfig();
void syncUiToSettings();
private slots:
void syncSettingsToUi();
void setRfPreset();
void setCompositePreset();
void setSvideoPreset();
void setRgbPreset();
void setMonoPreset();
private:
QWidget *widget;
QVBoxLayout *layout;
QGridLayout *gridLayout;
QLabel *basicSettings;
QLabel *hueLabel;
QLabel *hueValue;
QSlider *hueSlider;
QLabel *saturationLabel;
QLabel *saturationValue;
QSlider *saturationSlider;
QLabel *contrastLabel;
QLabel *contrastValue;
QSlider *contrastSlider;
QLabel *brightnessLabel;
QLabel *brightnessValue;
QSlider *brightnessSlider;
QLabel *sharpnessLabel;
QLabel *sharpnessValue;
QSlider *sharpnessSlider;
QLabel *advancedSettings;
QLabel *gammaLabel;
QLabel *gammaValue;
QSlider *gammaSlider;
QLabel *resolutionLabel;
QLabel *resolutionValue;
QSlider *resolutionSlider;
QLabel *artifactsLabel;
QLabel *artifactsValue;
QSlider *artifactsSlider;
QLabel *fringingLabel;
QLabel *fringingValue;
QSlider *fringingSlider;
QLabel *bleedLabel;
QLabel *bleedValue;
QSlider *bleedSlider;
QCheckBox *mergeFieldsBox;
QLabel *presets;
QHBoxLayout *controlLayout;
QPushButton *rfPreset;
QPushButton *compositePreset;
QPushButton *svideoPreset;
QPushButton *rgbPreset;
QPushButton *monoPreset;
QWidget *spacer;
QPushButton *ok;
bool blockSignals;
struct snes_ntsc_t *ntsc;
snes_ntsc_setup_t setup;
int burst, burst_toggle;
//settings
double hue;
double saturation;
double contrast;
double brightness;
double sharpness;
double gamma;
double resolution;
double artifacts;
double fringing;
double bleed;
bool mergeFields;
} filter_ntsc;

1
snesfilter/out/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*

View File

@ -1,12 +1,19 @@
#include "pixellate2x.hpp" #include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
void Pixellate2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { extern "C" {
outwidth = (width <= 256) ? width * 2 : width; void filter_size(unsigned&, unsigned&);
outheight = (height <= 240) ? height * 2 : height; void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
dllexport void filter_size(unsigned &width, unsigned &height) {
width = (width <= 256) ? width * 2 : width;
height = (height <= 240) ? height * 2 : height;
} }
void Pixellate2xFilter::render( dllexport void filter_render(
uint32_t *output, unsigned outpitch, uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) { ) {
pitch >>= 1; pitch >>= 1;

View File

@ -1,5 +0,0 @@
class Pixellate2xFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
} filter_pixellate2x;

View File

@ -1,20 +1,21 @@
#include "scale2x.hpp" #include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { extern "C" {
if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); void filter_size(unsigned&, unsigned&);
outwidth = width * 2; void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
outheight = height * 2; };
dllexport void filter_size(unsigned &width, unsigned &height) {
width *= 2;
height *= 2;
} }
void Scale2xFilter::render( dllexport void filter_render(
uint32_t *output, unsigned outpitch, uint32_t *colortable, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) { ) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, width, height);
return;
}
pitch >>= 1; pitch >>= 1;
outpitch >>= 2; outpitch >>= 2;
@ -27,9 +28,9 @@ void Scale2xFilter::render(
for(unsigned x = 0; x < width; x++) { for(unsigned x = 0; x < width; x++) {
uint16_t A = *(input - prevline); uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input; uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input; uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input; uint16_t D = (x < width - 1) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline); uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C]; uint32_t c = colortable[C];
@ -47,7 +48,7 @@ void Scale2xFilter::render(
} }
input += pitch - width; input += pitch - width;
out0 += outpitch + outpitch - 512; out0 += outpitch + outpitch - (width << 1);
out1 += outpitch + outpitch - 512; out1 += outpitch + outpitch - (width << 1);
} }
} }

View File

@ -1,5 +0,0 @@
class Scale2xFilter {
public:
void size(unsigned&, unsigned&, unsigned, unsigned);
void render(uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
} filter_scale2x;

View File

@ -0,0 +1,34 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
dllexport void filter_size(unsigned &width, unsigned &height) {
height *= 2;
}
dllexport void filter_render(
uint32_t *palette, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * pitch;
uint32_t *out0 = output + y * outpitch * 2;
uint32_t *out1 = output + y * outpitch * 2 + outpitch;
for(unsigned x = 0; x < width; x++) {
*out0++ = palette[*in++];
*out1++ = 0;
}
}
}

View File

@ -0,0 +1,55 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
uint16_t adjust[32768];
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
for(unsigned i = 0; i < 32768; i++) {
uint8_t r = (i >> 10) & 31;
uint8_t g = (i >> 5) & 31;
uint8_t b = (i >> 0) & 31;
r *= 0.25;
g *= 0.25;
b *= 0.25;
adjust[i] = (r << 10) + (g << 5) + (b << 0);
}
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
height *= 2;
}
dllexport void filter_render(
uint32_t *palette, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * pitch;
uint32_t *out0 = output + y * outpitch * 2;
uint32_t *out1 = output + y * outpitch * 2 + outpitch;
for(unsigned x = 0; x < width; x++) {
uint16_t color = *in++;
*out0++ = palette[color];
*out1++ = palette[adjust[color]];
}
}
}

View File

@ -0,0 +1,55 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
uint16_t adjust[32768];
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
for(unsigned i = 0; i < 32768; i++) {
uint8_t r = (i >> 10) & 31;
uint8_t g = (i >> 5) & 31;
uint8_t b = (i >> 0) & 31;
r *= 0.50;
g *= 0.50;
b *= 0.50;
adjust[i] = (r << 10) + (g << 5) + (b << 0);
}
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
height *= 2;
}
dllexport void filter_render(
uint32_t *palette, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * pitch;
uint32_t *out0 = output + y * outpitch * 2;
uint32_t *out1 = output + y * outpitch * 2 + outpitch;
for(unsigned x = 0; x < width; x++) {
uint16_t color = *in++;
*out0++ = palette[color];
*out1++ = palette[adjust[color]];
}
}
}

View File

@ -0,0 +1,55 @@
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
using namespace nall;
extern "C" {
void filter_size(unsigned&, unsigned&);
void filter_render(uint32_t*, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
};
uint16_t adjust[32768];
void initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
for(unsigned i = 0; i < 32768; i++) {
uint8_t r = (i >> 10) & 31;
uint8_t g = (i >> 5) & 31;
uint8_t b = (i >> 0) & 31;
r *= 0.75;
g *= 0.75;
b *= 0.75;
adjust[i] = (r << 10) + (g << 5) + (b << 0);
}
}
dllexport void filter_size(unsigned &width, unsigned &height) {
initialize();
height *= 2;
}
dllexport void filter_render(
uint32_t *palette, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
initialize();
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
const uint16_t *in = input + y * pitch;
uint32_t *out0 = output + y * outpitch * 2;
uint32_t *out1 = output + y * outpitch * 2 + outpitch;
for(unsigned x = 0; x < width; x++) {
uint16_t color = *in++;
*out0++ = palette[color];
*out1++ = palette[adjust[color]];
}
}
}

View File

@ -1,83 +0,0 @@
#include "snesfilter.hpp"
#if defined(_WIN32)
#define dllexport __declspec(dllexport)
#else
#define dllexport
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define QT_CORE_LIB
#include <QtGui>
#include <nall/config.hpp>
#include <nall/platform.hpp>
#include <nall/string.hpp>
using namespace nall;
const uint32_t *colortable;
configuration *config;
#include "direct/direct.cpp"
#include "pixellate2x/pixellate2x.cpp"
#include "scale2x/scale2x.cpp"
#include "2xsai/2xsai.cpp"
#include "lq2x/lq2x.cpp"
#include "hq2x/hq2x.cpp"
#include "ntsc/ntsc.cpp"
dllexport const char* snesfilter_supported() {
return "Pixellate2x;Scale2x;2xSaI;Super 2xSaI;Super Eagle;LQ2x;HQ2x;NTSC";
}
dllexport void snesfilter_configuration(configuration &config_) {
config = &config_;
if(config) {
filter_ntsc.bind(*config);
}
}
dllexport void snesfilter_colortable(const uint32_t *colortable_) {
colortable = colortable_;
}
dllexport void snesfilter_size(unsigned filter, unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
switch(filter) {
default: return filter_direct.size(outwidth, outheight, width, height);
case 1: return filter_pixellate2x.size(outwidth, outheight, width, height);
case 2: return filter_scale2x.size(outwidth, outheight, width, height);
case 3: return filter_2xsai.size(outwidth, outheight, width, height);
case 4: return filter_super2xsai.size(outwidth, outheight, width, height);
case 5: return filter_supereagle.size(outwidth, outheight, width, height);
case 6: return filter_lq2x.size(outwidth, outheight, width, height);
case 7: return filter_hq2x.size(outwidth, outheight, width, height);
case 8: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
dllexport void snesfilter_render(
unsigned filter, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
) {
switch(filter) {
default: return filter_direct.render(output, outpitch, input, pitch, width, height);
case 1: return filter_pixellate2x.render(output, outpitch, input, pitch, width, height);
case 2: return filter_scale2x.render(output, outpitch, input, pitch, width, height);
case 3: return filter_2xsai.render(output, outpitch, input, pitch, width, height);
case 4: return filter_super2xsai.render(output, outpitch, input, pitch, width, height);
case 5: return filter_supereagle.render(output, outpitch, input, pitch, width, height);
case 6: return filter_lq2x.render(output, outpitch, input, pitch, width, height);
case 7: return filter_hq2x.render(output, outpitch, input, pitch, width, height);
case 8: return filter_ntsc.render(output, outpitch, input, pitch, width, height);
}
}
dllexport QWidget* snesfilter_settings(unsigned filter) {
switch(filter) {
default: return 0;
case 8: return filter_ntsc.settings();
}
}

View File

@ -1,12 +0,0 @@
#include <stdint.h>
class QWidget;
namespace nall { class configuration; }
extern "C" {
const char* snesfilter_supported();
void snesfilter_configuration(nall::configuration&);
void snesfilter_colortable(const uint32_t*);
void snesfilter_size(unsigned, unsigned&, unsigned&, unsigned, unsigned);
void snesfilter_render(unsigned, uint32_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
QWidget* snesfilter_settings(unsigned);
}

View File

@ -1,2 +1,8 @@
rm -r nall synchronize() {
cp -r ../nall ./nall if [ -d ../"$1" ]; then
test -d "$1" && rm -r "$1"
cp -r ../"$1" ./"$1"
fi
}
synchronize "nall"