From 5ae0c80ee8fb91baf3b5b90f982f2ab5d7795513 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 26 Oct 2010 23:01:41 +1100 Subject: [PATCH] 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.) --- bsnes/Makefile | 2 +- bsnes/nall/dl.hpp | 19 + bsnes/nall/snes/info.hpp | 5 + bsnes/phoenix/gtk/gtk.cpp | 1 + bsnes/phoenix/gtk/gtk.hpp | 18 + bsnes/phoenix/gtk/hexeditor.cpp | 213 +++++++++++ bsnes/phoenix/gtk/object.cpp | 8 + bsnes/snes/snes.hpp | 2 +- bsnes/ui-phoenix/Makefile | 3 +- bsnes/ui-phoenix/base.hpp | 6 + bsnes/ui-phoenix/config.cpp | 1 + bsnes/ui-phoenix/config.hpp | 1 + bsnes/ui-phoenix/debugger/console.cpp | 30 ++ bsnes/ui-phoenix/debugger/console.hpp | 14 + bsnes/ui-phoenix/debugger/cpu/debugger.cpp | 44 +++ bsnes/ui-phoenix/debugger/cpu/debugger.hpp | 9 + bsnes/ui-phoenix/debugger/debugger.cpp | 69 ++++ bsnes/ui-phoenix/debugger/debugger.hpp | 21 ++ bsnes/ui-phoenix/general/file-browser.cpp | 5 + bsnes/ui-phoenix/general/file-browser.hpp | 2 +- bsnes/ui-phoenix/general/main-window.cpp | 8 + bsnes/ui-phoenix/general/main-window.hpp | 2 + bsnes/ui-phoenix/input/hotkeys.cpp | 5 + bsnes/ui-phoenix/interface.cpp | 26 +- bsnes/ui-phoenix/interface.hpp | 8 + bsnes/ui-phoenix/main.cpp | 23 +- bsnes/ui-phoenix/settings/video.cpp | 23 ++ bsnes/ui-phoenix/settings/video.hpp | 6 + bsnes/ui-phoenix/utility/utility.cpp | 14 + bsnes/ui-phoenix/utility/utility.hpp | 1 + snesfilter/2xsai/2xsai.cpp | 150 ++------ snesfilter/2xsai/2xsai.hpp | 35 -- snesfilter/2xsai/super-2xsai.cpp | 32 ++ snesfilter/2xsai/super-eagle.cpp | 32 ++ snesfilter/Makefile | 114 ++---- snesfilter/cc.bat | 2 - snesfilter/clean.bat | 1 - snesfilter/direct/direct.cpp | 23 -- snesfilter/direct/direct.hpp | 5 - snesfilter/hq2x/hq2x.cpp | 286 +++++++-------- snesfilter/hq2x/hq2x.hpp | 30 -- snesfilter/lq2x/lq2x.cpp | 33 +- snesfilter/lq2x/lq2x.hpp | 5 - snesfilter/nall/Makefile | 8 +- snesfilter/nall/config.hpp | 8 +- snesfilter/nall/dictionary.hpp | 10 +- snesfilter/nall/directory.hpp | 151 ++++++++ snesfilter/nall/dl.hpp | 47 +-- snesfilter/nall/file.hpp | 62 ++-- snesfilter/nall/filemap.hpp | 44 ++- snesfilter/nall/function.hpp | 116 +++--- snesfilter/nall/input.hpp | 6 +- snesfilter/nall/platform.hpp | 42 +++ snesfilter/nall/qt/Makefile | 55 --- snesfilter/nall/qt/check-action.moc.hpp | 41 --- snesfilter/nall/qt/concept.hpp | 10 - snesfilter/nall/qt/file-dialog.moc.hpp | 392 --------------------- snesfilter/nall/qt/hex-editor.moc.hpp | 173 --------- snesfilter/nall/qt/radio-action.moc.hpp | 41 --- snesfilter/nall/qt/window.moc.hpp | 105 ------ snesfilter/nall/serial.hpp | 11 +- snesfilter/nall/serializer.hpp | 1 + snesfilter/nall/snes/info.hpp | 7 +- snesfilter/nall/string.hpp | 5 +- snesfilter/nall/string/base.hpp | 85 +++-- snesfilter/nall/string/bsv.hpp | 75 ++++ snesfilter/nall/string/compare.hpp | 50 ++- snesfilter/nall/string/core.hpp | 34 +- snesfilter/nall/string/filename.hpp | 4 +- snesfilter/nall/string/match.hpp | 76 ---- snesfilter/nall/string/platform.hpp | 41 +++ snesfilter/nall/string/split.hpp | 6 +- snesfilter/nall/string/strpos.hpp | 4 +- snesfilter/nall/string/trim.hpp | 38 +- snesfilter/nall/string/utility.hpp | 12 - snesfilter/nall/string/variadic.hpp | 19 +- snesfilter/nall/string/wrapper.hpp | 33 ++ snesfilter/nall/string/xml.hpp | 23 +- snesfilter/nall/ups.hpp | 353 ++++++++++--------- snesfilter/nall/utf8.hpp | 16 +- snesfilter/nall/varint.hpp | 6 +- snesfilter/ntsc/ntsc-composite.cpp | 63 ++++ snesfilter/ntsc/ntsc-rf.cpp | 63 ++++ snesfilter/ntsc/ntsc-rgb.cpp | 63 ++++ snesfilter/ntsc/ntsc-svideo.cpp | 63 ++++ snesfilter/ntsc/ntsc.cpp | 380 -------------------- snesfilter/ntsc/ntsc.moc.hpp | 91 ----- snesfilter/out/.gitignore | 1 + snesfilter/pixellate2x/pixellate2x.cpp | 19 +- snesfilter/pixellate2x/pixellate2x.hpp | 5 - snesfilter/scale2x/scale2x.cpp | 33 +- snesfilter/scale2x/scale2x.hpp | 5 - snesfilter/scanline/scanline-00.cpp | 34 ++ snesfilter/scanline/scanline-25.cpp | 55 +++ snesfilter/scanline/scanline-50.cpp | 55 +++ snesfilter/scanline/scanline-75.cpp | 55 +++ snesfilter/snesfilter.cpp | 83 ----- snesfilter/snesfilter.hpp | 12 - snesfilter/sync.sh | 10 +- 99 files changed, 2209 insertions(+), 2428 deletions(-) create mode 100755 bsnes/phoenix/gtk/hexeditor.cpp create mode 100755 bsnes/ui-phoenix/debugger/console.cpp create mode 100755 bsnes/ui-phoenix/debugger/console.hpp create mode 100755 bsnes/ui-phoenix/debugger/cpu/debugger.cpp create mode 100755 bsnes/ui-phoenix/debugger/cpu/debugger.hpp create mode 100755 bsnes/ui-phoenix/debugger/debugger.cpp create mode 100755 bsnes/ui-phoenix/debugger/debugger.hpp delete mode 100755 snesfilter/2xsai/2xsai.hpp create mode 100755 snesfilter/2xsai/super-2xsai.cpp create mode 100755 snesfilter/2xsai/super-eagle.cpp delete mode 100755 snesfilter/cc.bat delete mode 100755 snesfilter/clean.bat delete mode 100755 snesfilter/direct/direct.cpp delete mode 100755 snesfilter/direct/direct.hpp delete mode 100755 snesfilter/hq2x/hq2x.hpp delete mode 100755 snesfilter/lq2x/lq2x.hpp create mode 100755 snesfilter/nall/directory.hpp delete mode 100755 snesfilter/nall/qt/Makefile delete mode 100755 snesfilter/nall/qt/check-action.moc.hpp delete mode 100755 snesfilter/nall/qt/concept.hpp delete mode 100755 snesfilter/nall/qt/file-dialog.moc.hpp delete mode 100755 snesfilter/nall/qt/hex-editor.moc.hpp delete mode 100755 snesfilter/nall/qt/radio-action.moc.hpp delete mode 100755 snesfilter/nall/qt/window.moc.hpp create mode 100755 snesfilter/nall/string/bsv.hpp delete mode 100755 snesfilter/nall/string/match.hpp create mode 100755 snesfilter/nall/string/platform.hpp create mode 100755 snesfilter/nall/string/wrapper.hpp create mode 100755 snesfilter/ntsc/ntsc-composite.cpp create mode 100755 snesfilter/ntsc/ntsc-rf.cpp create mode 100755 snesfilter/ntsc/ntsc-rgb.cpp create mode 100755 snesfilter/ntsc/ntsc-svideo.cpp delete mode 100755 snesfilter/ntsc/ntsc.cpp delete mode 100755 snesfilter/ntsc/ntsc.moc.hpp create mode 100644 snesfilter/out/.gitignore delete mode 100755 snesfilter/pixellate2x/pixellate2x.hpp delete mode 100755 snesfilter/scale2x/scale2x.hpp create mode 100755 snesfilter/scanline/scanline-00.cpp create mode 100755 snesfilter/scanline/scanline-25.cpp create mode 100755 snesfilter/scanline/scanline-50.cpp create mode 100755 snesfilter/scanline/scanline-75.cpp delete mode 100755 snesfilter/snesfilter.cpp delete mode 100755 snesfilter/snesfilter.hpp diff --git a/bsnes/Makefile b/bsnes/Makefile index a820d46f..1e08781e 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,6 +1,6 @@ include nall/Makefile snes := snes -profile := accuracy +profile := performance ui := ui-phoenix # compiler diff --git a/bsnes/nall/dl.hpp b/bsnes/nall/dl.hpp index 6fa7603f..ebfa5585 100755 --- a/bsnes/nall/dl.hpp +++ b/bsnes/nall/dl.hpp @@ -19,6 +19,7 @@ namespace nall { struct library { bool opened() const { return handle; } bool open(const char*, const char* = ""); + bool open_absolute(const char*); void* sym(const char*); void close(); @@ -40,6 +41,12 @@ namespace nall { 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) { if(!handle) return 0; return dlsym((void*)handle, name); @@ -58,6 +65,12 @@ namespace nall { 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) { if(!handle) return 0; return dlsym((void*)handle, name); @@ -76,6 +89,12 @@ namespace nall { 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) { if(!handle) return 0; return (void*)GetProcAddress((HMODULE)handle, name); diff --git a/bsnes/nall/snes/info.hpp b/bsnes/nall/snes/info.hpp index 67db4748..df8b5f59 100755 --- a/bsnes/nall/snes/info.hpp +++ b/bsnes/nall/snes/info.hpp @@ -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 uint8_t mapperid = data[index + Mapper]; const uint8_t rom_type = data[index + RomType]; diff --git a/bsnes/phoenix/gtk/gtk.cpp b/bsnes/phoenix/gtk/gtk.cpp index 381e3250..3c7cbb60 100755 --- a/bsnes/phoenix/gtk/gtk.cpp +++ b/bsnes/phoenix/gtk/gtk.cpp @@ -27,6 +27,7 @@ namespace phoenix { #include "checkbox.cpp" #include "combobox.cpp" #include "editbox.cpp" +#include "hexeditor.cpp" #include "horizontalslider.cpp" #include "label.cpp" #include "listbox.cpp" diff --git a/bsnes/phoenix/gtk/gtk.hpp b/bsnes/phoenix/gtk/gtk.hpp index 3ba82fe2..07f0d3ff 100755 --- a/bsnes/phoenix/gtk/gtk.hpp +++ b/bsnes/phoenix/gtk/gtk.hpp @@ -159,6 +159,24 @@ struct EditBox : Widget { void setText(const nall::string &text); }; +struct HexEditor : Widget { + nall::function onRead; + nall::function 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 { nall::function onChange; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length); diff --git a/bsnes/phoenix/gtk/hexeditor.cpp b/bsnes/phoenix/gtk/hexeditor.cpp new file mode 100755 index 00000000..6327626e --- /dev/null +++ b/bsnes/phoenix/gtk/hexeditor.cpp @@ -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); +} diff --git a/bsnes/phoenix/gtk/object.cpp b/bsnes/phoenix/gtk/object.cpp index f09960ac..28624012 100755 --- a/bsnes/phoenix/gtk/object.cpp +++ b/bsnes/phoenix/gtk/object.cpp @@ -35,6 +35,14 @@ struct Canvas::Data { unsigned pitch; }; +struct HexEditor::Data { + GtkTextMark *cursor; + unsigned size; + unsigned offset; + unsigned columns; + unsigned rows; +}; + struct ListBox::Data { GtkListStore *store; struct GtkColumn { diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 46f7a705..fc33ec4f 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "072"; + static const char Version[] = "072.01"; static const unsigned SerializerVersion = 14; } } diff --git a/bsnes/ui-phoenix/Makefile b/bsnes/ui-phoenix/Makefile index e0917522..71f14855 100755 --- a/bsnes/ui-phoenix/Makefile +++ b/bsnes/ui-phoenix/Makefile @@ -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 += $(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-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-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/*) $(call compile,$(rubydef) $(rubyflags)) diff --git a/bsnes/ui-phoenix/base.hpp b/bsnes/ui-phoenix/base.hpp index ceb2f492..ad66b8ac 100755 --- a/bsnes/ui-phoenix/base.hpp +++ b/bsnes/ui-phoenix/base.hpp @@ -29,15 +29,21 @@ struct TopLevelWindow : Window { #include "utility/utility.hpp" #include "cartridge/cartridge.hpp" +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" +#endif + struct Application { Font proportionalFont; Font proportionalFontBold; Font monospaceFont; + bool pause; bool quit; void main(int argc, char **argv); void addWindow(TopLevelWindow *window, const string &name, const string &position); + Application(); private: array windows; diff --git a/bsnes/ui-phoenix/config.cpp b/bsnes/ui-phoenix/config.cpp index 8c295440..f152345b 100755 --- a/bsnes/ui-phoenix/config.cpp +++ b/bsnes/ui-phoenix/config.cpp @@ -18,6 +18,7 @@ void Configuration::create() { attach(video.driver = "", "video.driver"); attach(video.synchronize = false, "video.synchronize"); attach(video.smooth = true, "video.smooth"); + attach(video.filter = "", "video.filter"); attach(video.shader = "", "video.shader"); attach(video.region = 0, "video.region"); attach(video.scale = 2, "video.scale"); diff --git a/bsnes/ui-phoenix/config.hpp b/bsnes/ui-phoenix/config.hpp index 72db7d2c..a30b6696 100755 --- a/bsnes/ui-phoenix/config.hpp +++ b/bsnes/ui-phoenix/config.hpp @@ -12,6 +12,7 @@ struct Configuration : public configuration { string driver; bool synchronize; bool smooth; + string filter; string shader; bool region; unsigned scale; diff --git a/bsnes/ui-phoenix/debugger/console.cpp b/bsnes/ui-phoenix/debugger/console.cpp new file mode 100755 index 00000000..e4712bf4 --- /dev/null +++ b/bsnes/ui-phoenix/debugger/console.cpp @@ -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); +} diff --git a/bsnes/ui-phoenix/debugger/console.hpp b/bsnes/ui-phoenix/debugger/console.hpp new file mode 100755 index 00000000..549a5562 --- /dev/null +++ b/bsnes/ui-phoenix/debugger/console.hpp @@ -0,0 +1,14 @@ +struct Console : TopLevelWindow { + EditBox output; + CheckBox traceToConsole; + CheckBox traceToDisk; + CheckBox traceCPU; + + string buffer; + + void create(); + void eventTraceCPU(); +}; + +extern Console console; + diff --git a/bsnes/ui-phoenix/debugger/cpu/debugger.cpp b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp new file mode 100755 index 00000000..1c7eed93 --- /dev/null +++ b/bsnes/ui-phoenix/debugger/cpu/debugger.cpp @@ -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", + " ..." + }); +} diff --git a/bsnes/ui-phoenix/debugger/cpu/debugger.hpp b/bsnes/ui-phoenix/debugger/cpu/debugger.hpp new file mode 100755 index 00000000..a39c4bac --- /dev/null +++ b/bsnes/ui-phoenix/debugger/cpu/debugger.hpp @@ -0,0 +1,9 @@ +struct CPUdebugger : TopLevelWindow { + EditBox output; + Button stepInto; + + void create(); + void eventStepInto(); +}; + +extern CPUdebugger cpuDebugger; diff --git a/bsnes/ui-phoenix/debugger/debugger.cpp b/bsnes/ui-phoenix/debugger/debugger.cpp new file mode 100755 index 00000000..41e68853 --- /dev/null +++ b/bsnes/ui-phoenix/debugger/debugger.cpp @@ -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 diff --git a/bsnes/ui-phoenix/debugger/debugger.hpp b/bsnes/ui-phoenix/debugger/debugger.hpp new file mode 100755 index 00000000..852c179e --- /dev/null +++ b/bsnes/ui-phoenix/debugger/debugger.hpp @@ -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; diff --git a/bsnes/ui-phoenix/general/file-browser.cpp b/bsnes/ui-phoenix/general/file-browser.cpp index bc6dedb4..2632a5e1 100755 --- a/bsnes/ui-phoenix/general/file-browser.cpp +++ b/bsnes/ui-phoenix/general/file-browser.cpp @@ -58,6 +58,11 @@ void FileBrowser::fileOpen(FileBrowser::Mode requestedMode, function callback); void create(); diff --git a/bsnes/ui-phoenix/general/main-window.cpp b/bsnes/ui-phoenix/general/main-window.cpp index 9f709685..e2fa68cc 100755 --- a/bsnes/ui-phoenix/general/main-window.cpp +++ b/bsnes/ui-phoenix/general/main-window.cpp @@ -96,6 +96,10 @@ void MainWindow::create() { toolsSeparator2.create(tools); toolsCheatEditor.create(tools, "Cheat Editor ..."); toolsStateManager.create(tools, "State Manager ..."); + #if defined(DEBUGGER) + toolsSeparator3.create(tools); + toolsDebugger.create(tools, "Debugger ..."); + #endif help.create(*this, "Help"); helpAbout.create(help, "About ..."); @@ -192,6 +196,10 @@ void MainWindow::create() { toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); }; toolsStateManager.onTick = []() { stateManager.setVisible(); }; + #if defined(DEBUGGER) + toolsDebugger.onTick = []() { debugger.setVisible(); }; + #endif + helpAbout.onTick = []() { MessageWindow::information(mainWindow, { "bsnes\n\n", diff --git a/bsnes/ui-phoenix/general/main-window.hpp b/bsnes/ui-phoenix/general/main-window.hpp index b27a5e0f..9c49970b 100755 --- a/bsnes/ui-phoenix/general/main-window.hpp +++ b/bsnes/ui-phoenix/general/main-window.hpp @@ -63,6 +63,8 @@ struct MainWindow : TopLevelWindow { MenuSeparator toolsSeparator2; MenuItem toolsCheatEditor; MenuItem toolsStateManager; + MenuSeparator toolsSeparator3; + MenuItem toolsDebugger; Menu help; MenuItem helpAbout; Viewport viewport; diff --git a/bsnes/ui-phoenix/input/hotkeys.cpp b/bsnes/ui-phoenix/input/hotkeys.cpp index df79be1c..d426f0cb 100755 --- a/bsnes/ui-phoenix/input/hotkeys.cpp +++ b/bsnes/ui-phoenix/input/hotkeys.cpp @@ -28,6 +28,11 @@ void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) { utility.showMessage({ "Slot ", activeSlot, " selected" }); } + //pause + if(scancode == keyboard(0)[Keyboard::P]) { + application.pause = !application.pause; + } + //fast forward if(scancode == keyboard(0)[Keyboard::Tilde]) { videoSync = config.video.synchronize; diff --git a/bsnes/ui-phoenix/interface.cpp b/bsnes/ui-phoenix/interface.cpp index 0a3766ac..e35af270 100755 --- a/bsnes/ui-phoenix/interface.cpp +++ b/bsnes/ui-phoenix/interface.cpp @@ -1,4 +1,5 @@ Palette palette; +Filter filter; Interface interface; 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) { bool interlace = (height >= 240); 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(video.lock(buffer, outpitch, width, height)) { - for(unsigned y = 0; y < height; y++) { - uint32_t *output = buffer + y * (outpitch >> 2); - const uint16_t *input = data + y * (inpitch >> 1); - for(unsigned x = 0; x < width; x++) *output++ = palette.color[*input++]; - } + unsigned outwidth = width, outheight = height; + filter.size(outwidth, outheight); + + if(video.lock(buffer, outpitch, outwidth, outheight)) { + filter.render(buffer, outpitch, data, inpitch, width, height); video.unlock(); video.refresh(); } diff --git a/bsnes/ui-phoenix/interface.hpp b/bsnes/ui-phoenix/interface.hpp index 7421f883..fbc22036 100755 --- a/bsnes/ui-phoenix/interface.hpp +++ b/bsnes/ui-phoenix/interface.hpp @@ -7,6 +7,13 @@ struct Palette { void update(); }; +struct Filter : public library { + function dl_size; + function 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 { void video_refresh(const uint16_t *data, unsigned width, unsigned height); void audio_sample(uint16_t left, uint16_t right); @@ -15,4 +22,5 @@ struct Interface : public SNES::Interface { }; extern Palette palette; +extern Filter filter; extern Interface interface; diff --git a/bsnes/ui-phoenix/main.cpp b/bsnes/ui-phoenix/main.cpp index 85129f32..09bb4b42 100755 --- a/bsnes/ui-phoenix/main.cpp +++ b/bsnes/ui-phoenix/main.cpp @@ -46,6 +46,10 @@ void Application::main(int argc, char **argv) { advancedSettings.create(); cheatEditor.create(); stateManager.create(); + #if defined(DEBUGGER) + debugger.create(); + #endif + loadGeometry(); saveGeometry(); @@ -86,6 +90,7 @@ void Application::main(int argc, char **argv) { } utility.setControllers(); + utility.setFilter(); utility.setShader(); if(argc == 2) cartridge.loadNormal(argv[1]); @@ -96,14 +101,15 @@ void Application::main(int argc, char **argv) { utility.updateStatus(); if(SNES::cartridge.loaded()) { - //pause emulator when main window is inactive? - if(config.settings.focusPolicy == 0) { - if(mainWindow.focused() == false) { - usleep(20 * 1000); - continue; - } + if(application.pause == true || (config.settings.focusPolicy == 0 && mainWindow.focused() == false)) { + usleep(20 * 1000); + continue; } + #if defined(DEBUGGER) + debugger.run(); + #else SNES::system.run(); + #endif } else { usleep(20 * 1000); } @@ -129,6 +135,11 @@ void Application::addWindow(TopLevelWindow *window, const string &name, const st geometryConfig.attach(window->position, window->name); } +Application::Application() { + pause = false; + quit = false; +} + int main(int argc, char **argv) { application.main(argc, argv); return 0; diff --git a/bsnes/ui-phoenix/settings/video.cpp b/bsnes/ui-phoenix/settings/video.cpp index 5487187d..768eb774 100755 --- a/bsnes/ui-phoenix/settings/video.cpp +++ b/bsnes/ui-phoenix/settings/video.cpp @@ -23,6 +23,15 @@ void VideoSettings::create() { 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.setFont(application.proportionalFontBold); @@ -42,6 +51,20 @@ void VideoSettings::create() { contrastSlider.onChange = brightnessSlider.onChange = gammaSlider.onChange = gammaRampCheck.onTick = { &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 = []() { config.video.shader = ""; videoSettings.shaderPath.setText(config.video.shader); diff --git a/bsnes/ui-phoenix/settings/video.hpp b/bsnes/ui-phoenix/settings/video.hpp index baf2f9d6..644e911d 100755 --- a/bsnes/ui-phoenix/settings/video.hpp +++ b/bsnes/ui-phoenix/settings/video.hpp @@ -10,6 +10,12 @@ struct VideoSettings : TopLevelWindow { Label gammaValue; HorizontalSlider gammaSlider; CheckBox gammaRampCheck; + + Label filterLabel; + TextBox filterPath; + Button filterClear; + Button filterSelect; + Label shaderLabel; TextBox shaderPath; Button shaderClear; diff --git a/bsnes/ui-phoenix/utility/utility.cpp b/bsnes/ui-phoenix/utility/utility.cpp index fc05b992..139b58fe 100755 --- a/bsnes/ui-phoenix/utility/utility.cpp +++ b/bsnes/ui-phoenix/utility/utility.cpp @@ -16,6 +16,10 @@ void Utility::updateStatus() { text = statusMessage; } else if(SNES::cartridge.loaded() == false) { text = "No cartridge loaded"; + } else if(application.pause) { + text = "Paused"; + } else if(config.settings.focusPolicy == 0 && mainWindow.focused() == false) { + text = "Auto-paused"; } else { text = statusText; } @@ -71,6 +75,16 @@ void Utility::setScale(unsigned scale) { 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() { string data; data.readfile(config.video.shader); diff --git a/bsnes/ui-phoenix/utility/utility.hpp b/bsnes/ui-phoenix/utility/utility.hpp index 454d4046..7d926444 100755 --- a/bsnes/ui-phoenix/utility/utility.hpp +++ b/bsnes/ui-phoenix/utility/utility.hpp @@ -6,6 +6,7 @@ struct Utility : property { void setControllers(); void setScale(unsigned scale = 0); + void setFilter(); void setShader(); void cartridgeLoaded(); diff --git a/snesfilter/2xsai/2xsai.cpp b/snesfilter/2xsai/2xsai.cpp index c58a27dc..13391053 100755 --- a/snesfilter/2xsai/2xsai.cpp +++ b/snesfilter/2xsai/2xsai.cpp @@ -1,132 +1,32 @@ -//2xSaI / Super 2xSaI / Super Eagle filter -//authors: kode54 and Kreed -//license: GPL +#include +#include +using namespace nall; -#include "2xsai.hpp" #include "implementation.cpp" -//===== -//2xSaI -//===== - -void _2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { - outwidth = width; - outheight = height; - - if(width <= 256 && height <= 240) { - outwidth *= 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; +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; } -//=========== -//Super 2xSaI -//=========== - -void Super2xSaIFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { - outwidth = width; - outheight = height; - - if(width <= 256 && height <= 240) { - 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; -} +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]]; + } + } -//=========== -//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; + _2xSaI32( (unsigned char *) temp, 2048, 0, (unsigned char *) output, outpitch, width, height ); } diff --git a/snesfilter/2xsai/2xsai.hpp b/snesfilter/2xsai/2xsai.hpp deleted file mode 100755 index 8f3031fb..00000000 --- a/snesfilter/2xsai/2xsai.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/2xsai/super-2xsai.cpp b/snesfilter/2xsai/super-2xsai.cpp new file mode 100755 index 00000000..1f27d9fb --- /dev/null +++ b/snesfilter/2xsai/super-2xsai.cpp @@ -0,0 +1,32 @@ +#include +#include +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 ); +} diff --git a/snesfilter/2xsai/super-eagle.cpp b/snesfilter/2xsai/super-eagle.cpp new file mode 100755 index 00000000..8fa376e1 --- /dev/null +++ b/snesfilter/2xsai/super-eagle.cpp @@ -0,0 +1,32 @@ +#include +#include +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 ); +} diff --git a/snesfilter/Makefile b/snesfilter/Makefile index 089b86ee..a71f7ad0 100755 --- a/snesfilter/Makefile +++ b/snesfilter/Makefile @@ -1,89 +1,51 @@ include nall/Makefile -qtlibs := QtCore QtGui -include nall/qt/Makefile +c := $(compiler) -std=gnu99 +cpp := $(subst cc,++,$(compiler)) -std=gnu++0x +flags := -O3 -I. -Iobj -fomit-frame-pointer -fPIC +link := -s +objects := -c := $(compiler) -std=gnu99 -cpp := $(subst cc,++,$(compiler)) -std=gnu++0x -flags := -O3 -I. -Iobj -fomit-frame-pointer $(qtinc) -link := +objects += out/pixellate2x.filter +objects += out/scanline-00.filter +objects += out/scanline-25.filter +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) - 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 +compile = $(cpp) $(link) $(flags) -o $@ -shared $< -objects := snesfilter - -compile = \ - $(strip \ - $(if $(filter %.c,$<), \ - $(c) $(flags) $1 -c $< -o $@, \ - $(if $(filter %.cpp,$<), \ - $(cpp) $(flags) $1 -c $< -o $@ \ - ) \ - ) \ - ) - -%.o: $<; $(call compile) +%.filter: $<; $(call compile) all: build; -objects := $(patsubst %,obj/%.o,$(objects)) -moc_headers := $(call rwildcard,./,%.moc.hpp) -moc_objects := $(foreach f,$(moc_headers),obj/$(notdir $(patsubst %.moc.hpp,%.moc,$f))) +out/pixellate2x.filter: pixellate2x/pixellate2x.cpp pixellate2x/* +out/scanline-00.filter: scanline/scanline-00.cpp scanline/* +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 -%.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 +build: $(objects) 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: - -@$(call delete,obj/*.o) - -@$(call delete,obj/*.moc) - -@$(call delete,libsnesfilter.a) - -@$(call delete,libsnesfilter.so) - -@$(call delete,libsnesfilter.dylib) - -@$(call delete,snesfilter.dll) diff --git a/snesfilter/cc.bat b/snesfilter/cc.bat deleted file mode 100755 index 8359a530..00000000 --- a/snesfilter/cc.bat +++ /dev/null @@ -1,2 +0,0 @@ -@mingw32-make -@pause \ No newline at end of file diff --git a/snesfilter/clean.bat b/snesfilter/clean.bat deleted file mode 100755 index d8bb7e0b..00000000 --- a/snesfilter/clean.bat +++ /dev/null @@ -1 +0,0 @@ -@mingw32-make clean diff --git a/snesfilter/direct/direct.cpp b/snesfilter/direct/direct.cpp deleted file mode 100755 index 7d582b16..00000000 --- a/snesfilter/direct/direct.cpp +++ /dev/null @@ -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; - } -} diff --git a/snesfilter/direct/direct.hpp b/snesfilter/direct/direct.hpp deleted file mode 100755 index 588a76e4..00000000 --- a/snesfilter/direct/direct.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/hq2x/hq2x.cpp b/snesfilter/hq2x/hq2x.cpp index 6e38feb0..08aec9b2 100755 --- a/snesfilter/hq2x/hq2x.cpp +++ b/snesfilter/hq2x/hq2x.cpp @@ -1,31 +1,157 @@ -//HQ2x filter -//authors: byuu and blargg -//license: public domain -// -//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 +#include +using namespace nall; -#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) { - if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); - outwidth = width * 2; - outheight = height * 2; -} +enum { + diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407, + diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0, +}; -void HQ2xFilter::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; +uint32_t *yuvTable; +uint8_t rotate[256]; + +const uint8_t 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, +}; + +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; outpitch >>= 2; - #pragma omp parallel for +//#pragma omp parallel for for(unsigned y = 0; y < height; y++) { const uint16_t *in = input + y * pitch; uint32_t *out0 = output + y * outpitch * 2; @@ -38,7 +164,7 @@ void HQ2xFilter::render( *out0++ = 0; *out0++ = 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 B = *(in - prevline + 0); uint16_t C = *(in - prevline + 1); @@ -75,121 +201,3 @@ void HQ2xFilter::render( *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, -}; diff --git a/snesfilter/hq2x/hq2x.hpp b/snesfilter/hq2x/hq2x.hpp deleted file mode 100755 index f48c47cd..00000000 --- a/snesfilter/hq2x/hq2x.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/lq2x/lq2x.cpp b/snesfilter/lq2x/lq2x.cpp index 560913e7..8015aa49 100755 --- a/snesfilter/lq2x/lq2x.cpp +++ b/snesfilter/lq2x/lq2x.cpp @@ -1,20 +1,21 @@ -#include "lq2x.hpp" +#include +#include +using namespace nall; -void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { - if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); - outwidth = width * 2; - outheight = height * 2; +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) { + width *= 2; + height *= 2; } -void LQ2xFilter::render( - uint32_t *output, unsigned outpitch, +dllexport void filter_render( + uint32_t *colortable, 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; - } - pitch >>= 1; outpitch >>= 2; @@ -27,9 +28,9 @@ void LQ2xFilter::render( for(unsigned x = 0; x < width; x++) { 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 D = (x < 255) ? *(input + 1) : *input; + uint16_t D = (x < width - 1) ? *(input + 1) : *input; uint16_t E = *(input++ + nextline); uint32_t c = colortable[C]; @@ -47,7 +48,7 @@ void LQ2xFilter::render( } input += pitch - width; - out0 += outpitch + outpitch - 512; - out1 += outpitch + outpitch - 512; + out0 += outpitch + outpitch - (width << 1); + out1 += outpitch + outpitch - (width << 1); } } diff --git a/snesfilter/lq2x/lq2x.hpp b/snesfilter/lq2x/lq2x.hpp deleted file mode 100755 index 5b1a0e41..00000000 --- a/snesfilter/lq2x/lq2x.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/nall/Makefile b/snesfilter/nall/Makefile index b761af22..9a93bd23 100755 --- a/snesfilter/nall/Makefile +++ b/snesfilter/nall/Makefile @@ -29,10 +29,12 @@ ifeq ($(platform),) endif ifeq ($(compiler),) - ifeq ($(platform),osx) - compiler := gcc-mp-4.4 - else + ifeq ($(platform),win) compiler := gcc + else ifeq ($(platform),osx) + compiler := gcc-mp-4.5 + else + compiler := gcc-4.5 endif endif diff --git a/snesfilter/nall/config.hpp b/snesfilter/nall/config.hpp index c713d0b0..f555158e 100755 --- a/snesfilter/nall/config.hpp +++ b/snesfilter/nall/config.hpp @@ -49,7 +49,7 @@ namespace nall { case signed_t: *(signed*)data = strsigned(s); break; case unsigned_t: *(unsigned*)data = strunsigned(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; part.qsplit(" = ", line[i]); - trim(part[0]); - trim(part[1]); + part[0].trim(); + part[1].trim(); for(unsigned n = 0; n < list.size(); n++) { if(part[0] == list[n].name) { @@ -102,7 +102,7 @@ namespace nall { virtual bool save(const char *filename) const { file fp; - if(fp.open(filename, file::mode_write)) { + if(fp.open(filename, file::mode::write)) { for(unsigned i = 0; i < list.size(); i++) { string output; output << list[i].name << " = " << list[i].get(); diff --git a/snesfilter/nall/dictionary.hpp b/snesfilter/nall/dictionary.hpp index 9e0a1620..dcb04151 100755 --- a/snesfilter/nall/dictionary.hpp +++ b/snesfilter/nall/dictionary.hpp @@ -27,7 +27,7 @@ namespace nall { bool import(const char *filename) { string data; 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", ""); lstring line; @@ -39,12 +39,12 @@ namespace nall { if(part.size() != 2) continue; //remove whitespace - trim(part[0]); - trim(part[1]); + part[0].trim(); + part[1].trim(); //remove quotes - trim_once(part[0], "\""); - trim_once(part[1], "\""); + part[0].trim<1>("\""); + part[1].trim<1>("\""); unsigned n = index_input.size(); index_input[n] = part[0]; diff --git a/snesfilter/nall/directory.hpp b/snesfilter/nall/directory.hpp new file mode 100755 index 00000000..df0bf086 --- /dev/null +++ b/snesfilter/nall/directory.hpp @@ -0,0 +1,151 @@ +#ifndef NALL_DIRECTORY_HPP +#define NALL_DIRECTORY_HPP + +#include +#include +#include + +#if defined(_WIN32) + #include +#else + #include + #include + #include +#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 diff --git a/snesfilter/nall/dl.hpp b/snesfilter/nall/dl.hpp index 22acf51f..6fa7603f 100755 --- a/snesfilter/nall/dl.hpp +++ b/snesfilter/nall/dl.hpp @@ -3,9 +3,9 @@ //dynamic linking support -#include #include #include +#include #include #if defined(PLATFORM_X) || defined(PLATFORM_OSX) @@ -18,7 +18,7 @@ namespace nall { struct library { bool opened() const { return handle; } - bool open(const char*); + bool open(const char*, const char* = ""); void* sym(const char*); void close(); @@ -33,20 +33,10 @@ namespace nall { }; #if defined(PLATFORM_X) - inline bool library::open(const char *name) { + inline bool library::open(const char *name, const char *path) { if(handle) close(); - char *t = new char[strlen(name) + 256]; - strcpy(t, "lib"); - 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; + handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); return handle; } @@ -61,20 +51,10 @@ namespace nall { handle = 0; } #elif defined(PLATFORM_OSX) - inline bool library::open(const char *name) { + inline bool library::open(const char *name, const char *path) { if(handle) close(); - char *t = new char[strlen(name) + 256]; - strcpy(t, "lib"); - 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; + handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); return handle; } @@ -89,13 +69,10 @@ namespace nall { handle = 0; } #elif defined(PLATFORM_WIN) - inline bool library::open(const char *name) { + inline bool library::open(const char *name, const char *path) { if(handle) close(); - char *t = new char[strlen(name) + 8]; - strcpy(t, name); - strcat(t, ".dll"); - handle = (uintptr_t)LoadLibraryW(utf16_t(t)); - delete[] t; + string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll"); + handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); return handle; } @@ -110,7 +87,7 @@ namespace nall { handle = 0; } #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::close() {} #endif diff --git a/snesfilter/nall/file.hpp b/snesfilter/nall/file.hpp index 4c8ca8ee..103c7d4a 100755 --- a/snesfilter/nall/file.hpp +++ b/snesfilter/nall/file.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include @@ -25,12 +26,12 @@ namespace nall { class file { public: - enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread }; - enum SeekMode { seek_absolute, seek_relative }; + enum class mode : unsigned { read, write, readwrite, writeread }; + enum class index : unsigned { absolute, relative }; uint8_t read() { 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 buffer_sync(); return buffer[(file_offset++) & buffer_mask]; @@ -58,8 +59,8 @@ namespace nall { } void write(uint8_t data) { - if(!fp) return; //file not open - if(file_mode == mode_read) return; //writes not permitted + if(!fp) return; //file not open + if(file_mode == mode::read) return; //writes not permitted buffer_sync(); buffer[(file_offset++) & buffer_mask] = data; buffer_dirty = true; @@ -83,9 +84,10 @@ namespace nall { while(length--) write(*buffer++); } - void print(const char *string) { - if(!string) return; - while(*string) write(*string++); + template void print(Args... args) { + string data(args...); + const char *p = data; + while(*p) write(*p++); } void flush() { @@ -93,19 +95,19 @@ namespace nall { fflush(fp); } - void seek(int offset, SeekMode mode = seek_absolute) { + void seek(int offset, index index_ = index::absolute) { if(!fp) return; //file not open buffer_flush(); uintmax_t req_offset = file_offset; - switch(mode) { - case seek_absolute: req_offset = offset; break; - case seek_relative: req_offset += offset; break; + switch(index_) { + case index::absolute: 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 > 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; } else { //pad file to requested location file_offset = file_size; @@ -172,20 +174,20 @@ namespace nall { return fp; } - bool open(const char *fn, FileMode mode) { + bool open(const char *fn, mode mode_) { if(fp) return false; - switch(file_mode = mode) { + switch(file_mode = mode_) { #if !defined(_WIN32) - case mode_read: fp = fopen(fn, "rb"); break; - case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering - case mode_readwrite: fp = fopen(fn, "rb+"); break; - case mode_writeread: fp = fopen(fn, "wb+"); break; + case mode::read: fp = fopen(fn, "rb"); break; + case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering + case mode::readwrite: fp = fopen(fn, "rb+"); break; + case mode::writeread: fp = fopen(fn, "wb+"); break; #else - case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); 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_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); 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::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break; + case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break; #endif } if(!fp) return false; @@ -211,7 +213,7 @@ namespace nall { fp = 0; file_offset = 0; file_size = 0; - file_mode = mode_read; + file_mode = mode::read; } ~file() { @@ -229,7 +231,7 @@ namespace nall { FILE *fp; unsigned file_offset; unsigned file_size; - FileMode file_mode; + mode file_mode; void buffer_sync() { if(!fp) return; //file not open @@ -243,14 +245,14 @@ namespace nall { } void buffer_flush() { - if(!fp) return; //file not open - if(file_mode == mode_read) return; //buffer cannot be written to - if(buffer_offset < 0) return; //buffer unused - if(buffer_dirty == false) return; //buffer unmodified since read + if(!fp) return; //file not open + if(file_mode == mode::read) return; //buffer cannot be written to + if(buffer_offset < 0) return; //buffer unused + if(buffer_dirty == false) return; //buffer unmodified since read fseek(fp, buffer_offset, SEEK_SET); unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); if(length) unsigned unused = fwrite(buffer, 1, length, fp); - buffer_offset = -1; //invalidate buffer + buffer_offset = -1; //invalidate buffer buffer_dirty = false; } }; diff --git a/snesfilter/nall/filemap.hpp b/snesfilter/nall/filemap.hpp index a05f0eb7..52acb2fa 100755 --- a/snesfilter/nall/filemap.hpp +++ b/snesfilter/nall/filemap.hpp @@ -19,14 +19,16 @@ namespace nall { class filemap { 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(); } unsigned size() const { return p_size; } - uint8_t* handle() { return p_handle; } - const uint8_t* handle() const { return p_handle; } + uint8_t* data() { return p_handle; } + const uint8_t* data() const { return p_handle; } 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(); } private: @@ -40,31 +42,35 @@ namespace nall { 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; - switch(mode) { + switch(mode_) { default: return false; - case mode_read: + case mode::read: desired_access = GENERIC_READ; creation_disposition = OPEN_EXISTING; flprotect = PAGE_READONLY; map_access = FILE_MAP_READ; break; - case mode_write: + case mode::write: //write access requires read access desired_access = GENERIC_WRITE; creation_disposition = CREATE_ALWAYS; flprotect = PAGE_READWRITE; map_access = FILE_MAP_ALL_ACCESS; break; - case mode_readwrite: + case mode::readwrite: desired_access = GENERIC_READ | GENERIC_WRITE; creation_disposition = OPEN_EXISTING; flprotect = PAGE_READWRITE; map_access = FILE_MAP_ALL_ACCESS; break; - case mode_writeread: + case mode::writeread: desired_access = GENERIC_READ | GENERIC_WRITE; creation_disposition = CREATE_NEW; flprotect = PAGE_READWRITE; @@ -122,30 +128,34 @@ namespace nall { 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; - switch(mode) { + switch(mode_) { default: return false; - case mode_read: + case mode::read: open_flags = O_RDONLY; mmap_flags = PROT_READ; break; - case mode_write: + case mode::write: open_flags = O_RDWR | O_CREAT; //mmap() requires read access mmap_flags = PROT_WRITE; break; - case mode_readwrite: + case mode::readwrite: open_flags = O_RDWR; mmap_flags = PROT_READ | PROT_WRITE; break; - case mode_writeread: + case mode::writeread: open_flags = O_RDWR | O_CREAT; mmap_flags = PROT_READ | PROT_WRITE; 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; struct stat p_stat; diff --git a/snesfilter/nall/function.hpp b/snesfilter/nall/function.hpp index 036e4c9e..645991fb 100755 --- a/snesfilter/nall/function.hpp +++ b/snesfilter/nall/function.hpp @@ -1,89 +1,59 @@ #ifndef NALL_FUNCTION_HPP #define NALL_FUNCTION_HPP -#include -#include - namespace nall { template class function; - template - class function { - private: - struct base1 { virtual void func1(P...) {} }; - struct base2 { virtual void func2(P...) {} }; - struct derived : base1, virtual base2 {}; + template class function { + struct container { + virtual R operator()(P... p) const = 0; + virtual container* copy() const = 0; + virtual ~container() {} + } *callback; - struct data_t { - R (*callback)(const data_t&, P...); - union { - R (*callback_global)(P...); - struct { - R (derived::*callback_member)(P...); - void *object; - }; - }; - } data; + struct global : container { + R (*function)(P...); + R operator()(P... p) const { return function(std::forward

(p)...); } + container* copy() const { return new global(function); } + global(R (*function)(P...)) : function(function) {} + }; - static R callback_global(const data_t &data, P... p) { - return data.callback_global(p...); - } + template struct member : container { + R (C::*function)(P...); + C *object; + R operator()(P... p) const { return (object->*function)(std::forward

(p)...); } + container* copy() const { return new member(function, object); } + member(R (C::*function)(P...), C *object) : function(function), object(object) {} + }; - template - static R callback_member(const data_t &data, P... p) { - return (((C*)data.object)->*((R (C::*&)(P...))data.callback_member))(p...); - } + template struct lambda : container { + L object; + R operator()(P... p) const { return object(std::forward

(p)...); } + container* copy() const { return new lambda(object); } + lambda(const L& object) : object(object) {} + }; public: - R operator()(P... p) const { return data.callback(data, p...); } - operator bool() const { return data.callback; } - void reset() { data.callback = 0; } + operator bool() const { return callback; } + R operator()(P... p) const { return (*callback)(std::forward

(p)...); } + 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); } - - //no pointer - function() { - data.callback = 0; - } - - //symbolic link pointer (nall/dl.hpp::sym, etc) - 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 - function(R (C::*callback)(P...), C *object) { - static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small"); - data.callback = &callback_member; - (R (C::*&)(P...))data.callback_member = callback; - data.object = object; - } - - //const member function pointer - template - 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; - (R (C::*&)(P...))data.callback_member = (R (C::*&)(P...))callback; - data.object = object; - } - - //lambda function pointer - template - function(T callback) { - static_assert(std::is_same::type>::value, "lambda mismatch"); - data.callback = &callback_global; - data.callback_global = (R (*)(P...))callback; - } + function() : callback(0) {} + function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); } + function(R (*function)(P...)) { callback = new global(function); } + template function(R (C::*function)(P...), C *object) { callback = new member(function, object); } + template function(R (C::*function)(P...) const, C *object) { callback = new member((R (C::*)(P...))function, object); } + template function(const L& object) { callback = new lambda(object); } + ~function() { if(callback) delete callback; } }; } diff --git a/snesfilter/nall/input.hpp b/snesfilter/nall/input.hpp index 83c4a484..28b10453 100755 --- a/snesfilter/nall/input.hpp +++ b/snesfilter/nall/input.hpp @@ -91,7 +91,7 @@ struct Keyboard { static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "KB")) return 0; - ltrim(s, "KB"); + s.ltrim("KB"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; @@ -188,7 +188,7 @@ struct Mouse { static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "MS")) return 0; - ltrim(s, "MS"); + s.ltrim("MS"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; @@ -312,7 +312,7 @@ struct Joypad { static uint16_t decode(const char *name) { string s(name); if(!strbegin(name, "JP")) return 0; - ltrim(s, "JP"); + s.ltrim("JP"); unsigned id = strunsigned(s); auto pos = strpos(s, "::"); if(!pos) return 0; diff --git a/snesfilter/nall/platform.hpp b/snesfilter/nall/platform.hpp index 68ed37ce..72eeec09 100755 --- a/snesfilter/nall/platform.hpp +++ b/snesfilter/nall/platform.hpp @@ -23,10 +23,12 @@ #include #include #undef interface + #define dllexport __declspec(dllexport) #else #include #include #include + #define dllexport #endif //================== @@ -76,5 +78,45 @@ #define alwaysinline inline #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 diff --git a/snesfilter/nall/qt/Makefile b/snesfilter/nall/qt/Makefile deleted file mode 100755 index 69e84960..00000000 --- a/snesfilter/nall/qt/Makefile +++ /dev/null @@ -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 diff --git a/snesfilter/nall/qt/check-action.moc.hpp b/snesfilter/nall/qt/check-action.moc.hpp deleted file mode 100755 index db378fe9..00000000 --- a/snesfilter/nall/qt/check-action.moc.hpp +++ /dev/null @@ -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 diff --git a/snesfilter/nall/qt/concept.hpp b/snesfilter/nall/qt/concept.hpp deleted file mode 100755 index 51cacef4..00000000 --- a/snesfilter/nall/qt/concept.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NALL_QT_CONCEPT_HPP -#define NALL_QT_CONCEPT_HPP - -#include - -namespace nall { - template struct has_count> { enum { value = true }; }; -} - -#endif diff --git a/snesfilter/nall/qt/file-dialog.moc.hpp b/snesfilter/nall/qt/file-dialog.moc.hpp deleted file mode 100755 index 6528289b..00000000 --- a/snesfilter/nall/qt/file-dialog.moc.hpp +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef NALL_QT_FILEDIALOG_HPP -#define NALL_QT_FILEDIALOG_HPP - -#include -#include -#include - -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 ¤t, 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(""); - 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 diff --git a/snesfilter/nall/qt/hex-editor.moc.hpp b/snesfilter/nall/qt/hex-editor.moc.hpp deleted file mode 100755 index d59f4be9..00000000 --- a/snesfilter/nall/qt/hex-editor.moc.hpp +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef NALL_QT_HEXEDITOR_HPP -#define NALL_QT_HEXEDITOR_HPP - -#include -#include -#include - -namespace nall { - -class HexEditor : public QTextEdit { - Q_OBJECT - -public: - function reader; - function 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 << "" << temp << "  "; - - for(unsigned x = 0; x < editorColumns; x++) { - if(offset >= editorSize) break; - sprintf(temp, "%.2x", reader ? reader(offset) : 0x00); - offset++; - output << "" << temp << ""; - if(x != (editorColumns - 1)) output << " "; - } - - if(y != (editorRows - 1)) output << "
"; - } - - 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 diff --git a/snesfilter/nall/qt/radio-action.moc.hpp b/snesfilter/nall/qt/radio-action.moc.hpp deleted file mode 100755 index a2bbca48..00000000 --- a/snesfilter/nall/qt/radio-action.moc.hpp +++ /dev/null @@ -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 diff --git a/snesfilter/nall/qt/window.moc.hpp b/snesfilter/nall/qt/window.moc.hpp deleted file mode 100755 index 0d3bf390..00000000 --- a/snesfilter/nall/qt/window.moc.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef NALL_QT_WINDOW_HPP -#define NALL_QT_WINDOW_HPP - -#include -#include - -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 diff --git a/snesfilter/nall/serial.hpp b/snesfilter/nall/serial.hpp index 6f5cf6d6..9ac8451a 100755 --- a/snesfilter/nall/serial.hpp +++ b/snesfilter/nall/serial.hpp @@ -23,7 +23,7 @@ namespace nall { return ::write(port, (void*)data, length); } - bool open(const char *portname, unsigned rate) { + bool open(const char *portname, unsigned rate, bool flowcontrol) { close(); 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 |= (IGNBRK | IGNPAR); attr.c_oflag &=~ (OPOST); - attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB); - attr.c_cflag |= (CS8 | CREAD | CLOCAL); + attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | 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; if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } diff --git a/snesfilter/nall/serializer.hpp b/snesfilter/nall/serializer.hpp index 9f816dfe..ff2337ab 100755 --- a/snesfilter/nall/serializer.hpp +++ b/snesfilter/nall/serializer.hpp @@ -112,6 +112,7 @@ namespace nall { imode = Size; idata = 0; isize = 0; + icapacity = 0; } serializer(unsigned capacity) { diff --git a/snesfilter/nall/snes/info.hpp b/snesfilter/nall/snes/info.hpp index a32ca18e..df8b5f59 100755 --- a/snesfilter/nall/snes/info.hpp +++ b/snesfilter/nall/snes/info.hpp @@ -9,7 +9,7 @@ public: inline snes_information(const uint8_t *data, unsigned size); -private: +//private: inline void read_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); @@ -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 uint8_t mapperid = data[index + Mapper]; const uint8_t rom_type = data[index + RomType]; diff --git a/snesfilter/nall/string.hpp b/snesfilter/nall/string.hpp index bb9b2a09..9acc2e9d 100755 --- a/snesfilter/nall/string.hpp +++ b/snesfilter/nall/string.hpp @@ -2,16 +2,18 @@ #define NALL_STRING_HPP #include +#include #include #include +#include #include #include #include #include #include -#include #include +#include #include #include #include @@ -19,6 +21,7 @@ #include #include #include +#include #include namespace nall { diff --git a/snesfilter/nall/string/base.hpp b/snesfilter/nall/string/base.hpp index 11f6c946..77f15e17 100755 --- a/snesfilter/nall/string/base.hpp +++ b/snesfilter/nall/string/base.hpp @@ -17,10 +17,43 @@ namespace nall { class string { public: inline void reserve(unsigned); - inline unsigned length() const; inline string& assign(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 inline string& ltrim(const char *key = " "); + template inline string& rtrim(const char *key = " "); + template inline string& trim (const char *key = " "); + + inline optional position(const char *key) const; + inline optional qposition(const char *key) const; + template inline string& operator= (T value); template inline string& operator<<(T value); @@ -38,16 +71,11 @@ namespace nall { inline string& operator=(const string&); inline string& operator=(string&&); - inline string(); - inline string(const char*); + template inline string(Args&&... args); inline string(const string&); inline string(string&&); inline ~string(); - inline bool readfile(const char*); - inline string& replace (const char*, const char*); - inline string& qreplace(const char*, const char*); - protected: char *data; unsigned size; @@ -62,9 +90,9 @@ namespace nall { public: template inline lstring& operator<<(T value); - inline int find(const char*); - inline void split (const char*, const char*, unsigned = 0); - inline void qsplit(const char*, const char*, unsigned = 0); + inline optional find(const char*) const; + template inline void split (const char*, const char*); + template inline void qsplit(const char*, const char*); lstring(); lstring(std::initializer_list); @@ -73,7 +101,9 @@ namespace nall { //compare.hpp inline char chrlower(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 stribegin(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 double strdouble (const char *str); - //match.hpp - inline bool match(const char *pattern, const char *str); - //math.hpp inline bool strint (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 inline unsigned strlcpy(char *dest, const char *src, unsigned length); inline unsigned strlcat(char *dest, const char *src, unsigned length); + //strpos.hpp + inline optional strpos(const char *str, const char *key); + inline optional qstrpos(const char *str, const char *key); + //trim.hpp - inline char* ltrim(char *str, const char *key = " "); - inline char* rtrim(char *str, const char *key = " "); - 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 = " "); + template inline char* ltrim(char *str, const char *key = " "); + template inline char* rtrim(char *str, const char *key = " "); + template inline char* trim (char *str, const char *key = " "); //utility.hpp inline unsigned strlcpy(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& 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 inline string strhex(uintmax_t value); template inline string strsigned(intmax_t value); template inline string strunsigned(uintmax_t value); @@ -129,8 +153,7 @@ namespace nall { inline string strdouble(double value); //variadic.hpp - template inline string sprint(Args... args); - template inline void print(Args... args); + template inline void print(Args&&... args); }; #endif diff --git a/snesfilter/nall/string/bsv.hpp b/snesfilter/nall/string/bsv.hpp new file mode 100755 index 00000000..d4b919e0 --- /dev/null +++ b/snesfilter/nall/string/bsv.hpp @@ -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 diff --git a/snesfilter/nall/string/compare.hpp b/snesfilter/nall/string/compare.hpp index bd289753..bce0895b 100755 --- a/snesfilter/nall/string/compare.hpp +++ b/snesfilter/nall/string/compare.hpp @@ -11,14 +11,52 @@ char chrupper(char c) { return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c; } -int stricmp(const char *dest, const char *src) { - while(*dest) { - if(chrlower(*dest) != chrlower(*src)) break; - dest++; - src++; +int stricmp(const char *str1, const char *str2) { + while(*str1) { + if(chrlower(*str1) != chrlower(*str2)) break; + str1++, str2++; } + 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) { diff --git a/snesfilter/nall/string/core.hpp b/snesfilter/nall/string/core.hpp index f69802e4..bad29030 100755 --- a/snesfilter/nall/string/core.hpp +++ b/snesfilter/nall/string/core.hpp @@ -11,10 +11,6 @@ void string::reserve(unsigned size_) { } } -unsigned string::length() const { - return strlen(data); -} - string& string::assign(const char *s) { unsigned length = strlen(s); reserve(length); @@ -29,6 +25,11 @@ string& string::append(const char *s) { 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 { return data; } @@ -63,15 +64,20 @@ string& string::operator=(string &&source) { return *this; } -string::string() { +static void istring(string &output) { +} + +template +static void istring(string &output, const T &value, Args&&... args) { + output.append(value); + istring(output, std::forward(args)...); +} + +template string::string(Args&&... args) { size = 64; data = (char*)malloc(size + 1); *data = 0; -} - -string::string(const char *value) { - size = strlen(value); - data = strdup(value); + istring(*this, std::forward(args)...); } string::string(const string &value) { @@ -86,7 +92,7 @@ string::string(string &&source) { } string::~string() { - free(data); + if(data) free(data); } bool string::readfile(const char *filename) { @@ -112,11 +118,11 @@ bool string::readfile(const char *filename) { return true; } -int lstring::find(const char *key) { +optional lstring::find(const char *key) const { 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() { diff --git a/snesfilter/nall/string/filename.hpp b/snesfilter/nall/string/filename.hpp index f3750760..93d605ae 100755 --- a/snesfilter/nall/string/filename.hpp +++ b/snesfilter/nall/string/filename.hpp @@ -3,7 +3,9 @@ namespace nall { -// "foo/bar.c" -> "foo/", "bar.c" -> "./" +// "foo/bar.c" -> "foo/" +// "foo/" -> "foo/" +// "bar.c" -> "./" inline string dir(char const *name) { string result = name; for(signed i = strlen(result); i >= 0; i--) { diff --git a/snesfilter/nall/string/match.hpp b/snesfilter/nall/string/match.hpp deleted file mode 100755 index d8cf702d..00000000 --- a/snesfilter/nall/string/match.hpp +++ /dev/null @@ -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 diff --git a/snesfilter/nall/string/platform.hpp b/snesfilter/nall/string/platform.hpp new file mode 100755 index 00000000..42c1a756 --- /dev/null +++ b/snesfilter/nall/string/platform.hpp @@ -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 diff --git a/snesfilter/nall/string/split.hpp b/snesfilter/nall/string/split.hpp index bb77dfcd..8d3ca877 100755 --- a/snesfilter/nall/string/split.hpp +++ b/snesfilter/nall/string/split.hpp @@ -3,7 +3,8 @@ namespace nall { -void lstring::split(const char *key, const char *src, unsigned limit) { +template void lstring::split(const char *key, const char *src) { + unsigned limit = Limit; reset(); 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; } -void lstring::qsplit(const char *key, const char *src, unsigned limit) { +template void lstring::qsplit(const char *key, const char *src) { + unsigned limit = Limit; reset(); int ssl = strlen(src), ksl = strlen(key); diff --git a/snesfilter/nall/string/strpos.hpp b/snesfilter/nall/string/strpos.hpp index 5d7e200a..1907a2f3 100755 --- a/snesfilter/nall/string/strpos.hpp +++ b/snesfilter/nall/string/strpos.hpp @@ -7,7 +7,7 @@ namespace nall { -optional inline strpos(const char *str, const char *key) { +optional strpos(const char *str, const char *key) { unsigned ssl = strlen(str), ksl = strlen(key); if(ksl > ssl) return { false, 0 }; @@ -18,7 +18,7 @@ optional inline strpos(const char *str, const char *key) { return { false, 0 }; } -optional inline qstrpos(const char *str, const char *key) { +optional qstrpos(const char *str, const char *key) { unsigned ssl = strlen(str), ksl = strlen(key); if(ksl > ssl) return { false, 0 }; diff --git a/snesfilter/nall/string/trim.hpp b/snesfilter/nall/string/trim.hpp index b13ab9ba..f5355d7d 100755 --- a/snesfilter/nall/string/trim.hpp +++ b/snesfilter/nall/string/trim.hpp @@ -3,7 +3,9 @@ namespace nall { -char* ltrim(char *str, const char *key) { +//limit defaults to zero, which will underflow on first compare; equivalent to no limit +template char* ltrim(char *str, const char *key) { + unsigned limit = Limit; if(!key || !*key) return str; while(strbegin(str, key)) { char *dest = str, *src = str + strlen(key); @@ -12,41 +14,23 @@ char* ltrim(char *str, const char *key) { if(!*dest) break; dest++; } + if(--limit == 0) break; } return str; } -char* rtrim(char *str, const char *key) { +template char* rtrim(char *str, const char *key) { + unsigned limit = Limit; if(!key || !*key) return str; - while(strend(str, key)) str[strlen(str) - strlen(key)] = 0; - return str; -} - -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++; - } + while(strend(str, key)) { + str[strlen(str) - strlen(key)] = 0; + if(--limit == 0) break; } return str; } -char* rtrim_once(char *str, const char *key) { - if(!key || !*key) return str; - 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); +template char* trim(char *str, const char *key) { + return ltrim(rtrim(str, key), key); } } diff --git a/snesfilter/nall/string/utility.hpp b/snesfilter/nall/string/utility.hpp index 2da2762b..d2bad881 100755 --- a/snesfilter/nall/string/utility.hpp +++ b/snesfilter/nall/string/utility.hpp @@ -25,18 +25,6 @@ string substr(const char *src, unsigned start, unsigned length) { 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 */ template string strhex(uintmax_t value) { diff --git a/snesfilter/nall/string/variadic.hpp b/snesfilter/nall/string/variadic.hpp index 13c477a8..6c027fc8 100755 --- a/snesfilter/nall/string/variadic.hpp +++ b/snesfilter/nall/string/variadic.hpp @@ -3,23 +3,8 @@ namespace nall { -static void isprint(string &output) { -} - -template -static void isprint(string &output, T value, Args... args) { - output << to_string(value); - isprint(output, args...); -} - -template inline string sprint(Args... args) { - string output; - isprint(output, args...); - return output; -} - -template inline void print(Args... args) { - printf("%s", (const char*)sprint(args...)); +template inline void print(Args&&... args) { + printf("%s", (const char*)string(std::forward(args)...)); } } diff --git a/snesfilter/nall/string/wrapper.hpp b/snesfilter/nall/string/wrapper.hpp new file mode 100755 index 00000000..eadf0a10 --- /dev/null +++ b/snesfilter/nall/string/wrapper.hpp @@ -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 string& string::ltrim(const char *key) { nall::ltrim(data, key); return *this; } +template string& string::rtrim(const char *key) { nall::rtrim(data, key); return *this; } +template string& string::trim (const char *key) { nall::trim (data, key); return *this; } + +optional string::position(const char *key) const { return strpos(data, key); } +optional string::qposition(const char *key) const { return qstrpos(data, key); } + +} + +#endif diff --git a/snesfilter/nall/string/xml.hpp b/snesfilter/nall/string/xml.hpp index 6a4c672d..185a89f9 100755 --- a/snesfilter/nall/string/xml.hpp +++ b/snesfilter/nall/string/xml.hpp @@ -75,11 +75,12 @@ inline string xml_element::parse() const { if(strbegin(source, "")) { - string cdata = substr(source, 9, pos() - 9); - data << cdata; - offset += strlen(cdata); - - source += offset + 3; + if(pos() - 9 > 0) { + string cdata = substr(source, 9, pos() - 9); + data << cdata; + offset += strlen(cdata); + } + source += 9 + offset + 3; continue; } else { return ""; @@ -122,7 +123,7 @@ inline bool xml_element::parse_head(string data) { while(qstrpos(data, " ")) data.qreplace(" ", " "); data.qreplace(" =", "="); data.qreplace("= ", "="); - rtrim(data); + data.rtrim(); lstring part; part.qsplit(" ", data); @@ -138,8 +139,8 @@ inline bool xml_element::parse_head(string data) { xml_attribute attr; attr.name = side[0]; attr.content = side[1]; - if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) trim_once(attr.content, "\""); - else 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, "'")) attr.content.trim<1>("'"); else throw "..."; attribute.append(attr); } @@ -185,10 +186,10 @@ inline bool xml_element::parse_body(const char *&data) { if(strend(tag, "?") == true) { self_terminating = true; - rtrim_once(tag, "?"); + tag.rtrim<1>("?"); } else if(strend(tag, "/") == true) { self_terminating = true; - rtrim_once(tag, "/"); + tag.rtrim<1>("/"); } parse_head(tag); @@ -213,7 +214,7 @@ inline bool xml_element::parse_body(const char *&data) { tag.replace("\r", " "); tag.replace("\n", " "); while(strpos(tag, " ")) tag.replace(" ", " "); - rtrim(tag); + tag.rtrim(); if(name != tag) throw "..."; return true; diff --git a/snesfilter/nall/ups.hpp b/snesfilter/nall/ups.hpp index f255ecb3..ffcdb2d7 100755 --- a/snesfilter/nall/ups.hpp +++ b/snesfilter/nall/ups.hpp @@ -1,190 +1,223 @@ #ifndef NALL_UPS_HPP #define NALL_UPS_HPP -#include - -#include #include #include +#include #include 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) { - if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable; +struct ups { + 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; - uint32_t x_crc32 = crc32_calculate(x_data, x_size); - uint32_t y_crc32 = crc32_calculate(y_data, y_size); + function progress; - //header - write('U'); - write('P'); - write('S'); - write('1'); - encptr(x_size); - encptr(y_size); + result create( + const uint8_t *sourcedata, unsigned sourcelength, + const uint8_t *targetdata, unsigned targetlength, + const char *patchfilename + ) { + source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata; + source_length = sourcelength, target_length = targetlength; + source_offset = target_offset = 0; + source_checksum = target_checksum = patch_checksum = ~0; - //body - 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(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable; - if(x == y) { - i++; - continue; - } + patch_write('U'); + patch_write('P'); + patch_write('S'); + patch_write('1'); + encode(source_length); + encode(target_length); - encptr(i++ - relative); - write(x ^ y); + unsigned output_length = source_length > target_length ? source_length : target_length; + unsigned relative = 0; + for(unsigned offset = 0; offset < output_length;) { + uint8_t x = source_read(); + uint8_t y = target_read(); - while(true) { - if(i >= max_size) { - write(0x00); - 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; + if(x == y) { + offset++; + continue; } - //footer - for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3)); - 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)); + encode(offset++ - relative); + patch_write(x ^ y); - 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) { - uint64_t x = offset & 0x7f; - offset >>= 7; - if(offset == 0) { - write(0x80 | x); + if(offset >= output_length) { + patch_write(0x00); break; } - write(x); - offset--; + + x = source_read(); + y = target_read(); + offset++; + patch_write(x ^ y); + if(x == y) break; } + + relative = offset; } - uint64_t decptr() { - uint64_t offset = 0, shift = 1; + source_checksum = ~source_checksum; + 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) { - uint8_t x = read(); - offset += (x & 0x7f) * shift; - if(x & 0x80) break; - shift <<= 7; - offset += shift; + uint8_t patch_xor = patch_read(); + target_write(patch_xor ^ source_read()); + if(patch_xor == 0) break; } - 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 diff --git a/snesfilter/nall/utf8.hpp b/snesfilter/nall/utf8.hpp index c66c341a..f5597b85 100755 --- a/snesfilter/nall/utf8.hpp +++ b/snesfilter/nall/utf8.hpp @@ -6,9 +6,11 @@ #if defined(_WIN32) +#undef UNICODE #undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 #undef NOMINMAX +#define UNICODE +#define _WIN32_WINNT 0x0501 #define NOMINMAX #include #undef interface @@ -62,9 +64,21 @@ namespace nall { delete[] buffer; } + utf8_t(const utf8_t&) = delete; + utf8_t& operator=(const utf8_t&) = delete; + private: 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) diff --git a/snesfilter/nall/varint.hpp b/snesfilter/nall/varint.hpp index cc3bb17c..fe4732b1 100755 --- a/snesfilter/nall/varint.hpp +++ b/snesfilter/nall/varint.hpp @@ -1,9 +1,9 @@ #ifndef NALL_VARINT_HPP #define NALL_VARINT_HPP +#include #include #include -#include namespace nall { template class uint_t { @@ -22,7 +22,7 @@ namespace nall { >::type >::type >::type T; - static_assert::value> uint_assert; + static_assert(!std::is_same::value, ""); T data; public: @@ -63,7 +63,7 @@ namespace nall { >::type >::type >::type T; - static_assert::value> int_assert; + static_assert(!std::is_same::value, ""); T data; public: diff --git a/snesfilter/ntsc/ntsc-composite.cpp b/snesfilter/ntsc/ntsc-composite.cpp new file mode 100755 index 00000000..0e0ba16c --- /dev/null +++ b/snesfilter/ntsc/ntsc-composite.cpp @@ -0,0 +1,63 @@ +#include +#include +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; +} diff --git a/snesfilter/ntsc/ntsc-rf.cpp b/snesfilter/ntsc/ntsc-rf.cpp new file mode 100755 index 00000000..57929c92 --- /dev/null +++ b/snesfilter/ntsc/ntsc-rf.cpp @@ -0,0 +1,63 @@ +#include +#include +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; +} diff --git a/snesfilter/ntsc/ntsc-rgb.cpp b/snesfilter/ntsc/ntsc-rgb.cpp new file mode 100755 index 00000000..9067df75 --- /dev/null +++ b/snesfilter/ntsc/ntsc-rgb.cpp @@ -0,0 +1,63 @@ +#include +#include +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; +} diff --git a/snesfilter/ntsc/ntsc-svideo.cpp b/snesfilter/ntsc/ntsc-svideo.cpp new file mode 100755 index 00000000..9fe8f9d3 --- /dev/null +++ b/snesfilter/ntsc/ntsc-svideo.cpp @@ -0,0 +1,63 @@ +#include +#include +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; +} diff --git a/snesfilter/ntsc/ntsc.cpp b/snesfilter/ntsc/ntsc.cpp deleted file mode 100755 index 3db8a34a..00000000 --- a/snesfilter/ntsc/ntsc.cpp +++ /dev/null @@ -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("Basic settings:"); - 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("Advanced settings:"); - 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("Presets:"); - 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); -} diff --git a/snesfilter/ntsc/ntsc.moc.hpp b/snesfilter/ntsc/ntsc.moc.hpp deleted file mode 100755 index e8aba423..00000000 --- a/snesfilter/ntsc/ntsc.moc.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/out/.gitignore b/snesfilter/out/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/snesfilter/out/.gitignore @@ -0,0 +1 @@ +* diff --git a/snesfilter/pixellate2x/pixellate2x.cpp b/snesfilter/pixellate2x/pixellate2x.cpp index ca8f79f3..f57c5c39 100755 --- a/snesfilter/pixellate2x/pixellate2x.cpp +++ b/snesfilter/pixellate2x/pixellate2x.cpp @@ -1,12 +1,19 @@ -#include "pixellate2x.hpp" +#include +#include +using namespace nall; -void Pixellate2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { - outwidth = (width <= 256) ? width * 2 : width; - outheight = (height <= 240) ? height * 2 : height; +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) { + width = (width <= 256) ? width * 2 : width; + height = (height <= 240) ? height * 2 : height; } -void Pixellate2xFilter::render( - uint32_t *output, unsigned outpitch, +dllexport void filter_render( + uint32_t *colortable, uint32_t *output, unsigned outpitch, const uint16_t *input, unsigned pitch, unsigned width, unsigned height ) { pitch >>= 1; diff --git a/snesfilter/pixellate2x/pixellate2x.hpp b/snesfilter/pixellate2x/pixellate2x.hpp deleted file mode 100755 index 5ba2a1da..00000000 --- a/snesfilter/pixellate2x/pixellate2x.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/scale2x/scale2x.cpp b/snesfilter/scale2x/scale2x.cpp index c9bf0520..16f8231f 100755 --- a/snesfilter/scale2x/scale2x.cpp +++ b/snesfilter/scale2x/scale2x.cpp @@ -1,20 +1,21 @@ -#include "scale2x.hpp" +#include +#include +using namespace nall; -void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) { - if(width > 256 || height > 240) return filter_direct.size(outwidth, outheight, width, height); - outwidth = width * 2; - outheight = height * 2; +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) { + width *= 2; + height *= 2; } -void Scale2xFilter::render( - uint32_t *output, unsigned outpitch, +dllexport void filter_render( + uint32_t *colortable, 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; - } - pitch >>= 1; outpitch >>= 2; @@ -27,9 +28,9 @@ void Scale2xFilter::render( for(unsigned x = 0; x < width; x++) { 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 D = (x < 255) ? *(input + 1) : *input; + uint16_t D = (x < width - 1) ? *(input + 1) : *input; uint16_t E = *(input++ + nextline); uint32_t c = colortable[C]; @@ -47,7 +48,7 @@ void Scale2xFilter::render( } input += pitch - width; - out0 += outpitch + outpitch - 512; - out1 += outpitch + outpitch - 512; + out0 += outpitch + outpitch - (width << 1); + out1 += outpitch + outpitch - (width << 1); } } diff --git a/snesfilter/scale2x/scale2x.hpp b/snesfilter/scale2x/scale2x.hpp deleted file mode 100755 index 58f7b1bb..00000000 --- a/snesfilter/scale2x/scale2x.hpp +++ /dev/null @@ -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; diff --git a/snesfilter/scanline/scanline-00.cpp b/snesfilter/scanline/scanline-00.cpp new file mode 100755 index 00000000..7b9d6265 --- /dev/null +++ b/snesfilter/scanline/scanline-00.cpp @@ -0,0 +1,34 @@ +#include +#include +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; + } + } +} diff --git a/snesfilter/scanline/scanline-25.cpp b/snesfilter/scanline/scanline-25.cpp new file mode 100755 index 00000000..f9d655d3 --- /dev/null +++ b/snesfilter/scanline/scanline-25.cpp @@ -0,0 +1,55 @@ +#include +#include +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]]; + } + } +} diff --git a/snesfilter/scanline/scanline-50.cpp b/snesfilter/scanline/scanline-50.cpp new file mode 100755 index 00000000..f9e0445e --- /dev/null +++ b/snesfilter/scanline/scanline-50.cpp @@ -0,0 +1,55 @@ +#include +#include +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]]; + } + } +} diff --git a/snesfilter/scanline/scanline-75.cpp b/snesfilter/scanline/scanline-75.cpp new file mode 100755 index 00000000..263a840e --- /dev/null +++ b/snesfilter/scanline/scanline-75.cpp @@ -0,0 +1,55 @@ +#include +#include +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]]; + } + } +} diff --git a/snesfilter/snesfilter.cpp b/snesfilter/snesfilter.cpp deleted file mode 100755 index 30045474..00000000 --- a/snesfilter/snesfilter.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "snesfilter.hpp" - -#if defined(_WIN32) - #define dllexport __declspec(dllexport) -#else - #define dllexport -#endif - -#include -#include -#include - -#define QT_CORE_LIB -#include - -#include -#include -#include -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(); - } -} diff --git a/snesfilter/snesfilter.hpp b/snesfilter/snesfilter.hpp deleted file mode 100755 index 8c390dff..00000000 --- a/snesfilter/snesfilter.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#include -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); -} diff --git a/snesfilter/sync.sh b/snesfilter/sync.sh index 4bbaf34f..b51e3b40 100755 --- a/snesfilter/sync.sh +++ b/snesfilter/sync.sh @@ -1,2 +1,8 @@ -rm -r nall -cp -r ../nall ./nall +synchronize() { + if [ -d ../"$1" ]; then + test -d "$1" && rm -r "$1" + cp -r ../"$1" ./"$1" + fi +} + +synchronize "nall"