From 6497a54aad9e977da3755464393bc0817b69f3ad Mon Sep 17 00:00:00 2001 From: wowzaman12 Date: Sun, 5 Apr 2015 13:32:12 +0000 Subject: [PATCH] read kega fusion plugins in the wxwidgets interface and also started some work on xbrz support in the interface, will complete that later though. git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@1301 a31d4220-a93d-0410-bf67-fe4944624d44 --- src/wx/cmdevents.cpp | 7 ++ src/wx/guiinit.cpp | 249 ++++++++++++++++++++++++++++++++++--------- src/wx/opts.cpp | 3 +- src/wx/opts.h | 1 + src/wx/panel.cpp | 88 +++++++++++++-- src/wx/wxvbam.h | 1 + src/wx/wxvbam.xrc | 17 +++ 7 files changed, 308 insertions(+), 58 deletions(-) diff --git a/src/wx/cmdevents.cpp b/src/wx/cmdevents.cpp index c8322836..33d52bb7 100644 --- a/src/wx/cmdevents.cpp +++ b/src/wx/cmdevents.cpp @@ -2000,6 +2000,13 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY) EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY) { + int filt = gopts.filter; + if(filt == FF_PLUGIN || + ++gopts.filter == FF_PLUGIN && gopts.filter_plugin.empty()) + { + gopts.filter = 0; + } + update_opts(); if(panel->panel) { panel->panel->Delete(); panel->panel = NULL; diff --git a/src/wx/guiinit.cpp b/src/wx/guiinit.cpp index a363c134..e660b140 100644 --- a/src/wx/guiinit.cpp +++ b/src/wx/guiinit.cpp @@ -1438,6 +1438,145 @@ private: wxArrayVideoModes vm; }; +// enable plugin-related iff filter choice is plugin +class PluginEnabler : public wxValidator +{ +public: + PluginEnabler() : wxValidator() {} + PluginEnabler(const PluginEnabler &e) : wxValidator() {} + wxObject *Clone() const { return new PluginEnabler(*this); } + bool TransferFromWindow() { return true; } + bool Validate(wxWindow *p) { return true; } + bool TransferToWindow() + { + GetWindow()->Enable(gopts.filter == FF_PLUGIN); + return true; + } +}; + +// The same, but as an event handler +static class PluginEnable_t : public wxEvtHandler +{ +public: + wxWindow *lab, *ch; + void ToggleChoice(wxCommandEvent &ev) + { + bool en = ev.GetSelection() == FF_PLUGIN; + lab->Enable(en); + ch->Enable(en); + } +} PluginEnableHandler; + +// fill in plugin list +class PluginListFiller : public PluginEnabler +{ +public: + PluginListFiller(wxDialog *parent, wxControl *lab, wxChoice *ch) : + PluginEnabler(), txt(lab), dlg(parent), plugins(), filtch(ch) {} + PluginListFiller(const PluginListFiller &e) : + PluginEnabler(), txt(e.txt), dlg(e.dlg), plugins(e.plugins), + filtch(e.filtch) {} + wxObject *Clone() const { return new PluginListFiller(*this); } + bool Validate(wxWindow *p) { return true; } + bool TransferToWindow() + { + PluginEnabler::TransferToWindow(); + wxChoice *ch = wxStaticCast(GetWindow(), wxChoice); + ch->Clear(); + ch->Append(_("None")); + plugins.clear(); + const wxString &plpath = wxStandardPaths::Get().GetPluginsDir(); + wxDir::GetAllFiles(plpath, &plugins, wxT("*.rpi")); + for(int i = 0; i < plugins.size(); i++) { + wxDynamicLibrary dl(plugins[i], wxDL_VERBATIM|wxDL_NOW); + RENDPLUG_GetInfo GetInfo; + const RENDER_PLUGIN_INFO *rpi; + if(dl.IsLoaded() && + (GetInfo = (RENDPLUG_GetInfo)dl.GetSymbol(wxT("RenderPluginGetInfo"))) && + // note that in actual kega fusion plugins, rpi->Output is + // unused (as is rpi->Handle) + dl.GetSymbol(wxT("RenderPluginOutput")) && + (rpi = GetInfo()) && + // FIXME: maybe this should be >= RPI_VERISON + (rpi->Flags & 0xff) == RPI_VERSION && + // RPI_565_SUPP is not supported + // although it would be possible + // and it would make Cairo more efficient + (rpi->Flags & (RPI_555_SUPP|RPI_888_SUPP))) { + wxFileName fn(plugins[i]); + wxString s = fn.GetName(); + s += wxT(": "); + s += wxString(rpi->Name, wxConvUTF8, sizeof(rpi->Name)); + fn.MakeRelativeTo(plpath); + plugins[i] = fn.GetFullName(); + ch->Append(s); + if(plugins[i] == gopts.filter_plugin) + ch->SetSelection(i + 1); + } else + plugins.RemoveAt(i--); + } + if(ch->GetCount() == 1) { + // this is probably the only place the user can find out where + // to put the plugins... it depends on where program was + // installed, and of course OS + wxString msg; + msg.Printf(_("No usable rpi plugins found in %s"), plpath.c_str()); + systemScreenMessage(msg); + ch->Hide(); + txt->Hide(); + int cursel = filtch->GetSelection(); + if(cursel == FF_PLUGIN) + cursel = 0; + if(filtch->GetCount() == FF_PLUGIN + 1) { + filtch->Delete(FF_PLUGIN); + // apparently wxgtk loses selection after this, even + // if selection was not FF_PLUGIN + filtch->SetSelection(cursel); + } + } else { + ch->Show(); + txt->Show(); + if(filtch->GetCount() < FF_PLUGIN + 1) + filtch->Append(_("Plugin")); + } + // FIXME: this isn't enough. It only resizes 2nd time around + dlg->Fit(); + return true; + } + bool TransferFromWindow() + { + wxChoice *ch = wxStaticCast(GetWindow(), wxChoice); + if(ch->GetCount() == 1) { + gopts.filter_plugin = wxEmptyString; + // this happens if "Plugin" was selected and the entry was + // subsequently removed + if(ch->GetSelection() < 0) + ch->SetSelection(0); + if(gopts.filter < 0) + gopts.filter = 0; + } else { + int n = ch->GetSelection(); + if(n > 0) + gopts.filter_plugin = plugins[n - 1]; + else { + if(filtch->GetSelection() == FF_PLUGIN) { + wxMessageBox(_("Please select a plugin or a different filter"), + _("Plugin selection error"), wxOK|wxICON_ERROR); + return false; + } + gopts.filter_plugin = wxEmptyString; + } + } + return true; + } +private: + wxDialog *dlg; + wxControl *txt; + wxChoice *filtch; + wxArrayString plugins; +}; + + // this is the cmd table index for the accel tree ctrl // one of the "benefits" of using TreeItemData is that we have to // malloc them all, because treectrl destructor will free them all @@ -1459,15 +1598,15 @@ static bool treeid_to_name(int id, wxString &name, wxTreeCtrl *tc, wxTreeItemIdValue cookie; for(wxTreeItemId tid = tc->GetFirstChild(parent, cookie); tid.IsOk(); tid = tc->GetNextChild(parent, cookie)) { - const TreeInt *ti = static_cast(tc->GetItemData(tid)); - if(ti && ti->val == id) { - name = wxString(wxT(' '), 2 * lev) + tc->GetItemText(tid); - return true; - } - if(treeid_to_name(id, name, tc, tid, lev + 1)) { - name = wxString(wxT(' '), 2 * lev) + tc->GetItemText(tid) + wxT('\n') + name; - return true; - } + const TreeInt *ti = static_cast(tc->GetItemData(tid)); + if(ti && ti->val == id) { + name = wxString(wxT(' '), 2 * lev) + tc->GetItemText(tid); + return true; + } + if(treeid_to_name(id, name, tc, tid, lev + 1)) { + name = wxString(wxT(' '), 2 * lev) + tc->GetItemText(tid) + wxT('\n') + name; + return true; + } } return false; } @@ -2650,57 +2789,69 @@ bool MainFrame::InitMore(void) d=LoadXRCropertySheetDialog("DisplayConfig"); { - /// On-Screen Display - ch=GetValidatedChild(d, "SpeedIndicator",wxGenericValidator(& gopts.osd_speed)); - getcbb("NoStatusMsg", gopts.no_osd_status); - getcbb("Transparent", gopts.osd_transparent); + /// On-Screen Display + ch=GetValidatedChild(d, "SpeedIndicator",wxGenericValidator(& gopts.osd_speed)); + getcbb("NoStatusMsg", gopts.no_osd_status); + getcbb("Transparent", gopts.osd_transparent); - /// Zoom - // this was a choice, but I'd rather not have to make an off-by-one - // validator just for this, and spinctrl is good enough. - getsc("DefaultScale", gopts.video_scale); - getcbb("RetainAspect", gopts.retain_aspect); - getsc("MaxScale", gopts.max_scale); - // fs modes should be filled in at popup time - // since they may change based on what screen is current - SafeXRCCTRL(d, "FullscreenMode"); - getcbb("Fullscreen", gopts.fullscreen); + /// Zoom + // this was a choice, but I'd rather not have to make an off-by-one + // validator just for this, and spinctrl is good enough. + getsc("DefaultScale", gopts.video_scale); + getcbb("RetainAspect", gopts.retain_aspect); + getsc("MaxScale", gopts.max_scale); + // fs modes should be filled in at popup time + // since they may change based on what screen is current + SafeXRCCTRL(d, "FullscreenMode"); + getcbb("Fullscreen", gopts.fullscreen); - /// Advanced - getrbi("OutputSimple", gopts.render_method, RND_SIMPLE); - getrbi("OutputOpenGL", gopts.render_method, RND_OPENGL); + /// Advanced + getrbi("OutputSimple", gopts.render_method, RND_SIMPLE); + getrbi("OutputOpenGL", gopts.render_method, RND_OPENGL); #ifdef NO_OGL - rb->Hide(); + rb->Hide(); #endif - getrbi("OutputCairo", gopts.render_method, RND_CAIRO); + getrbi("OutputCairo", gopts.render_method, RND_CAIRO); #ifdef NO_CAIRO - rb->Hide(); + rb->Hide(); #endif - getrbi("OutputDirect3D", gopts.render_method, RND_DIRECT3D); + getrbi("OutputDirect3D", gopts.render_method, RND_DIRECT3D); #if !defined(__WXMSW__) || defined(NO_D3D) || 1 // not implemented - rb->Hide(); + rb->Hide(); #endif - getcbb("Bilinear", gopts.bilinear); - getcbb("VSync", gopts.vsync); - // FIXME: make cb disabled when not GL or d3d - int mthr = wxThread::GetCPUCount(); - if(mthr > 8) - mthr = 8; - if(mthr < 0) - mthr = 2; - cb=SafeXRCCTRL(d, "Multithread"); - cb->SetValidator(wxBoolIntValidator(&gopts.max_threads, mthr)); - if(mthr <= 1) - cb->Hide(); + getcbb("Bilinear", gopts.bilinear); + getcbb("VSync", gopts.vsync); + // FIXME: make cb disabled when not GL or d3d + int mthr = wxThread::GetCPUCount(); + if(mthr > 8) + mthr = 8; + if(mthr < 0) + mthr = 2; + cb=SafeXRCCTRL(d, "Multithread"); + cb->SetValidator(wxBoolIntValidator(&gopts.max_threads, mthr)); + if(mthr <= 1) + cb->Hide(); #ifdef MMX - getcbb("MMX", cpu_mmx); + getcbb("MMX", cpu_mmx); #else - cb=SafeXRCCTRL(d, "MMX"); - cb->Hide(); + cb=SafeXRCCTRL(d, "MMX"); + cb->Hide(); #endif - ch=GetValidatedChild(d, "Filter",wxGenericValidator(& gopts.filter)); - ch=GetValidatedChild(d, "IFB",wxGenericValidator(& gopts.ifb)); - d->Fit(); + ch=GetValidatedChild(d, "Filter",wxGenericValidator(& gopts.filter)); + // these two are filled and/or hidden at dialog load time + wxControl *pll; + wxChoice *pl; + pll=SafeXRCCTRL(d, "PluginLab"); + pl=SafeXRCCTRL(d, "Plugin"); + pll->SetValidator(PluginEnabler()); + pl->SetValidator(PluginListFiller(d, pll, ch)); + PluginEnableHandler.lab = pll; + PluginEnableHandler.ch = pl; + ch->Connect(wxEVT_COMMAND_CHOICE_SELECTED, + wxCommandEventHandler(PluginEnable_t::ToggleChoice), + NULL, &PluginEnableHandler); + ch=GetValidatedChild(d, "IFB",wxGenericValidator(& gopts.ifb)); + d->Fit(); } d=LoadXRCropertySheetDialog("SoundConfig"); diff --git a/src/wx/opts.cpp b/src/wx/opts.cpp index 2775fcf0..90214b8e 100644 --- a/src/wx/opts.cpp +++ b/src/wx/opts.cpp @@ -136,7 +136,8 @@ opt_desc opts[] = { ENUMOPT("Display/Filter", wxTRANSLATE("Full-screen filter to apply"), gopts.filter, wxTRANSLATE("none|2xsai|super2xsai|supereagle|pixelate|advmame|" "bilinear|bilinearplus|scanlines|tvmode|hq2x|lq2x|" - "simple2x|simple3x|hq3x|simple4x|hq4x")), + "simple2x|simple3x|hq3x|simple4x|hq4x|xbrz|plugin")), + STROPT ("Display/FilterPlugin", wxTRANSLATE("Filter plugin library"), gopts.filter_plugin), BOOLOPT("Display/Fullscreen", wxTRANSLATE("Enter fullscreen mode at startup"), gopts.fullscreen), INTOPT ("Display/FullscreenDepth", wxTRANSLATE("Fullscreen mode color depth (0 = any)"), gopts.fs_mode.bpp, 0, 999), INTOPT ("Display/FullscreenFreq", wxTRANSLATE("Fullscreen mode frequency (0 = any)"), gopts.fs_mode.refresh, 0, 999), diff --git a/src/wx/opts.h b/src/wx/opts.h index a2a8aada..66fcd418 100644 --- a/src/wx/opts.h +++ b/src/wx/opts.h @@ -15,6 +15,7 @@ extern struct opts_t { bool cpu_mmx; bool no_osd_status; int filter; + wxString filter_plugin; int ifb; bool fullscreen; wxVideoMode fs_mode; diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp index af8f6106..d8f2a21e 100644 --- a/src/wx/panel.cpp +++ b/src/wx/panel.cpp @@ -988,9 +988,47 @@ DrawingPanel::DrawingPanel(int _width, int _height) : pixbuf1(0), pixbuf2(0), rpi(0), nthreads(0) { memset(delta, 0xff, sizeof(delta)); - - scale = builtin_ff_scale(gopts.filter); + if(gopts.filter == FF_PLUGIN) { + do { // do { } while(0) so break; exits entire block + // could've also just used goto & a label, I guess + gopts.filter = FF_NONE; // preemptive in case of errors + systemColorDepth = 32; + if(gopts.filter_plugin.empty()) + break; + wxFileName fpn(gopts.filter_plugin); + fpn.MakeAbsolute(wxStandardPaths::Get().GetPluginsDir()); + if(!filt_plugin.Load(fpn.GetFullPath(), wxDL_VERBATIM|wxDL_NOW)) + break; + RENDPLUG_GetInfo gi = (RENDPLUG_GetInfo)filt_plugin.GetSymbol(wxT("RenderPluginGetInfo")); + if(!gi) + break; + // need to be able to write to _rpi to set Output() and Flags + RENDER_PLUGIN_INFO *_rpi = gi(); + // FIXME: maybe < RPI_VERSION, assuming future vers. back compat? + if(!_rpi || (_rpi->Flags & 0xff) != RPI_VERSION || + !(_rpi->Flags & (RPI_555_SUPP|RPI_888_SUPP))) + break; + _rpi->Flags &= ~RPI_565_SUPP; + if(_rpi->Flags & RPI_888_SUPP) { + _rpi->Flags &= ~RPI_555_SUPP; + // FIXME: should this be 32 or 24? No docs or sample source + systemColorDepth = 32; + } else + systemColorDepth = 16; + if(!_rpi->Output) + // note that in actual kega fusion plugins, rpi->Output is + // unused (as is rpi->Handle) + _rpi->Output = (RENDPLUG_Output)filt_plugin.GetSymbol(wxT("RenderPluginOutput")); + scale = (_rpi->Flags & RPI_OUT_SCLMSK) >> RPI_OUT_SCLSH; + rpi = _rpi; + gopts.filter = FF_PLUGIN; // now that there is a valid plugin + } while(0); + else { + scale = builtin_ff_scale(gopts.filter); #define out_16 (systemColorDepth == 16) +#endif + systemColorDepth = 32; + } systemColorDepth = 32; // Intialize color tables #if wxBYTE_ORDER == wxLITTLE_ENDIAN @@ -1149,9 +1187,6 @@ public: case FF_TV: ScanlinesTV32(src, instride, delta, dst, outstride, width, height); break; - case FF_HQ2X: - hq2x32(src, instride, delta, dst, outstride, width, height); - break; case FF_LQ2X: lq2x32(src, instride, delta, dst, outstride, width, height); break; @@ -1161,15 +1196,52 @@ public: case FF_SIMPLE3X: Simple3x32(src, instride, delta, dst, outstride, width, height); break; - case FF_HQ3X: - hq3x32(src, instride, delta, dst, outstride, width, height); - break; case FF_SIMPLE4X: Simple4x32(src, instride, delta, dst, outstride, width, height); break; + case FF_HQ2X: + hq2x32(src, instride, delta, dst, outstride, width, height); + break; + case FF_HQ3X: + hq3x32(src, instride, delta, dst, outstride, width, height); + break; case FF_HQ4X: hq4x32(src, instride, delta, dst, outstride, width, height); break; +/* Placeholder for xbrz support + case FF_XBRZ2X: + break; + case FF_XBRZ3X: + break; + case FF_XBRZ4X: + break; + case FF_XBRZ5X: + break; +*/ + case FF_PLUGIN: + // MFC interface did not do plugins in parallel + // Probably because it's almost certain they carry state or do + // other non-thread-safe things + // But the user can always turn mt off of it's not working.. + RENDER_PLUGIN_OUTP outdesc; + outdesc.Size = sizeof(outdesc); + outdesc.Flags = rpi->Flags; + outdesc.SrcPtr = src; + outdesc.SrcPitch = instride; + outdesc.SrcW = width; + // FIXME: win32 code adds to H, saying that frame isn't fully + // rendered otherwise + // I need to verify that statement before I go adding stuff that + // may make it crash. + outdesc.SrcH = height; // + scale / 2 + outdesc.DstPtr = dst; + outdesc.DstPitch = outstride; + outdesc.DstW = width * scale; + // on the other hand, there is at least 1 line below, so I'll add + // that to dest in case safety checks in plugin use < instead of <= + outdesc.DstH = height * scale + 1; // + scale * (scale / 2) + rpi->Output(&outdesc); + break; default: break; } diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h index b0102f78..1f05943f 100644 --- a/src/wx/wxvbam.h +++ b/src/wx/wxvbam.h @@ -508,6 +508,7 @@ protected: FilterThread *threads; int nthreads; wxSemaphore filt_done; + wxDynamicLibrary filt_plugin; const RENDER_PLUGIN_INFO *rpi; // also flag indicating plugin loaded // largest buffer required is 32-bit * (max width + 1) * (max height + 2) u8 delta[257 * 4 * 226]; diff --git a/src/wx/wxvbam.xrc b/src/wx/wxvbam.xrc index feff4b94..f8276a4e 100644 --- a/src/wx/wxvbam.xrc +++ b/src/wx/wxvbam.xrc @@ -2663,8 +2663,25 @@ HQ 3x Simple 4x HQ 4x + XBR 2x (note: Not available yet) + XBR 3x (note: Not available yet) + XBR 4x (note: Not available yet) + XBR 5x (note: Not available yet) + Plugin + wxALL|wxEXPAND + 5 + + + + + + wxALL|wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL + 5 + + + wxALL|wxEXPAND 5