From ee6501fbc0cc1dfb0fbb68ee50fa9ed227f3aa0f Mon Sep 17 00:00:00 2001 From: riccardom Date: Fri, 15 Feb 2013 21:01:03 +0000 Subject: [PATCH] Add filters support to the gtk frontend From Alberto, #3603211 --- desmume/src/commandline.cpp | 10 +-- desmume/src/gtk/Makefile.am | 6 ++ desmume/src/gtk/main.cpp | 118 +++++++++++++++++++++++++++++------- 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/desmume/src/commandline.cpp b/desmume/src/commandline.cpp index 2a072c9e3..7de2f9beb 100644 --- a/desmume/src/commandline.cpp +++ b/desmume/src/commandline.cpp @@ -28,7 +28,7 @@ #include "NDSSystem.h" #include "utils/xstring.h" -int scanline_filter_a = 0, scanline_filter_b = 2, scanline_filter_c = 2, scanline_filter_d = 4; +int _scanline_filter_a = 0, _scanline_filter_b = 2, _scanline_filter_c = 2, _scanline_filter_d = 4; int _commandline_linux_nojoy = 0; CommandLine::CommandLine() @@ -91,10 +91,10 @@ void CommandLine::loadCommonOptions() { "bios-swi", 0, 0, G_OPTION_ARG_INT, &_bios_swi, "Uses SWI from the provided bios files", "BIOS_SWI"}, { "spu-advanced", 0, 0, G_OPTION_ARG_INT, &_spu_advanced, "Uses advanced SPU capture functions", "SPU_ADVANCED"}, { "num-cores", 0, 0, G_OPTION_ARG_INT, &_num_cores, "Override numcores detection and use this many", "NUM_CORES"}, - { "scanline-filter-a", 0, 0, G_OPTION_ARG_INT, &scanline_filter_a, "Intensity of fadeout for scanlines filter (topleft) (default 0)", "SCANLINE_FILTER_A"}, - { "scanline-filter-b", 0, 0, G_OPTION_ARG_INT, &scanline_filter_b, "Intensity of fadeout for scanlines filter (topright) (default 2)", "SCANLINE_FILTER_B"}, - { "scanline-filter-c", 0, 0, G_OPTION_ARG_INT, &scanline_filter_c, "Intensity of fadeout for scanlines filter (bottomleft) (default 2)", "SCANLINE_FILTER_C"}, - { "scanline-filter-d", 0, 0, G_OPTION_ARG_INT, &scanline_filter_d, "Intensity of fadeout for scanlines filter (bottomright) (default 4)", "SCANLINE_FILTER_D"}, + { "scanline-filter-a", 0, 0, G_OPTION_ARG_INT, &_scanline_filter_a, "Intensity of fadeout for scanlines filter (topleft) (default 0)", "SCANLINE_FILTER_A"}, + { "scanline-filter-b", 0, 0, G_OPTION_ARG_INT, &_scanline_filter_b, "Intensity of fadeout for scanlines filter (topright) (default 2)", "SCANLINE_FILTER_B"}, + { "scanline-filter-c", 0, 0, G_OPTION_ARG_INT, &_scanline_filter_c, "Intensity of fadeout for scanlines filter (bottomleft) (default 2)", "SCANLINE_FILTER_C"}, + { "scanline-filter-d", 0, 0, G_OPTION_ARG_INT, &_scanline_filter_d, "Intensity of fadeout for scanlines filter (bottomright) (default 4)", "SCANLINE_FILTER_D"}, { "rigorous-timing", 0, 0, G_OPTION_ARG_INT, &_rigorous_timing, "Use some rigorous timings instead of unrealistically generous (default 0)", "RIGOROUS_TIMING"}, { "advanced-timing", 0, 0, G_OPTION_ARG_INT, &_advanced_timing, "Use advanced BUS-level timing (default 1)", "ADVANCED_TIMING"}, { "slot1", 0, 0, G_OPTION_ARG_STRING, &_slot1, "Device to load in slot 1 (default retail)", "SLOT1"}, diff --git a/desmume/src/gtk/Makefile.am b/desmume/src/gtk/Makefile.am index 754204d1d..4cdf643a3 100644 --- a/desmume/src/gtk/Makefile.am +++ b/desmume/src/gtk/Makefile.am @@ -18,6 +18,12 @@ desmume_SOURCES = \ ../driver.h ../driver.cpp \ osmesa_3Demu.cpp osmesa_3Demu.h \ cheatsGTK.h cheatsGTK.cpp \ + ../filter/hq2x.cpp ../filter/hq2x.h \ + ../filter/hq4x.cpp ../filter/hq4x.h \ + ../filter/2xsai.cpp ../filter/bilinear.cpp \ + ../filter/epx.cpp ../filter/lq2x.cpp \ + ../filter/scanline.cpp \ + ../filter/videofilter.cpp ../filter/videofilter.h \ main.cpp main.h desmume_LDADD = ../libdesmume.a \ $(SDL_LIBS) $(GTK_LIBS) $(GTHREAD_LIBS) $(ALSA_LIBS) $(LIBAGG_LIBS) $(LIBSOUNDTOUCH_LIBS) diff --git a/desmume/src/gtk/main.cpp b/desmume/src/gtk/main.cpp index 5bc2c39d7..cbe4260aa 100644 --- a/desmume/src/gtk/main.cpp +++ b/desmume/src/gtk/main.cpp @@ -53,6 +53,8 @@ #include "addons.h" +#include "filter/videofilter.h" + #ifdef GDB_STUB #include "gdbstub.h" #endif @@ -81,6 +83,8 @@ #define FPS_LIMITER_FRAME_PERIOD 8 static SDL_sem *fps_limiter_semaphore; static int gtk_fps_limiter_disabled; +extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline_filter_d; +VideoFilter video(256, 384, VideoFilterTypeID_HQ2XS, 4); enum { MAIN_BG_0 = 0, @@ -237,9 +241,31 @@ static const char *ui_description = " " " " " " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " " " " " +" " " " +" " " " " " " " @@ -300,7 +326,8 @@ static const GtkActionEntry action_entries[] = { { "editjoyctrls", NULL, "Edit _Joystick controls",NULL, NULL, Edit_Joystick_Controls }, { "RotationMenu", NULL, "_Rotation" }, { "OrientationMenu", NULL, "_Orientation" }, - { "InterpolationMenu", NULL, "_Interpolation" }, + { "PriInterpolationMenu", NULL, "Primary _Interpolation" }, + { "InterpolationMenu", NULL, "Secondary _Interpolation" }, { "ViewMenu", NULL, "_View" }, { "ToolsMenu", NULL, "_Tools" }, @@ -322,9 +349,32 @@ static const GtkToggleActionEntry toggle_entries[] = { { "fullscreen", NULL, "Fullscreen", "f", NULL, G_CALLBACK(ToggleFullscreen), FALSE}, }; +static const GtkRadioActionEntry pri_interpolation_entries[] = { + { "pri_interp_none", NULL, VideoFilterAttributesList[VideoFilterTypeID_None].typeString, NULL, NULL, VideoFilterTypeID_None}, + { "pri_interp_nearest2x", NULL, VideoFilterAttributesList[VideoFilterTypeID_Nearest2X].typeString, NULL, NULL, VideoFilterTypeID_Nearest2X}, + { "pri_interp_lq2x", NULL, VideoFilterAttributesList[VideoFilterTypeID_LQ2X].typeString, NULL, NULL, VideoFilterTypeID_LQ2X}, + { "pri_interp_lq2xs", NULL, VideoFilterAttributesList[VideoFilterTypeID_LQ2XS].typeString, NULL, NULL, VideoFilterTypeID_LQ2XS}, + { "pri_interp_hq2x", NULL, VideoFilterAttributesList[VideoFilterTypeID_HQ2X].typeString, NULL, NULL, VideoFilterTypeID_HQ2X}, + { "pri_interp_hq4x", NULL, VideoFilterAttributesList[VideoFilterTypeID_HQ4X].typeString, NULL, NULL, VideoFilterTypeID_HQ4X}, + { "pri_interp_hq2xs", NULL, VideoFilterAttributesList[VideoFilterTypeID_HQ2XS].typeString, NULL, NULL, VideoFilterTypeID_HQ2XS}, + { "pri_interp_2xsai", NULL, VideoFilterAttributesList[VideoFilterTypeID_2xSaI].typeString, NULL, NULL, VideoFilterTypeID_2xSaI}, + { "pri_interp_super2xsai", NULL, VideoFilterAttributesList[VideoFilterTypeID_Super2xSaI].typeString, NULL, NULL, VideoFilterTypeID_Super2xSaI}, + { "pri_interp_supereagle", NULL, VideoFilterAttributesList[VideoFilterTypeID_SuperEagle].typeString, NULL, NULL, VideoFilterTypeID_SuperEagle}, + { "pri_interp_scanline", NULL, VideoFilterAttributesList[VideoFilterTypeID_Scanline].typeString, NULL, NULL, VideoFilterTypeID_Scanline}, + { "pri_interp_bilinear", NULL, VideoFilterAttributesList[VideoFilterTypeID_Bilinear].typeString, NULL, NULL, VideoFilterTypeID_Bilinear}, + { "pri_interp_epx", NULL, VideoFilterAttributesList[VideoFilterTypeID_EPX].typeString, NULL, NULL, VideoFilterTypeID_EPX}, + { "pri_interp_epxplus", NULL, VideoFilterAttributesList[VideoFilterTypeID_EPXPlus].typeString, NULL, NULL, VideoFilterTypeID_EPXPlus}, + { "pri_interp_epx_1point5x", NULL, VideoFilterAttributesList[VideoFilterTypeID_EPX1_5X].typeString, NULL, NULL, VideoFilterTypeID_EPX1_5X}, + { "pri_interp_epxplus_1point5x", NULL, VideoFilterAttributesList[VideoFilterTypeID_EPXPlus1_5X].typeString, NULL, NULL, VideoFilterTypeID_EPXPlus1_5X}, + { "pri_interp_nearest_1point5x", NULL, VideoFilterAttributesList[VideoFilterTypeID_Nearest1_5X].typeString, NULL, NULL, VideoFilterTypeID_Nearest1_5X}, + { "pri_interp_nearestplus_1point5x", NULL, VideoFilterAttributesList[VideoFilterTypeID_NearestPlus1_5X].typeString, NULL, NULL, VideoFilterTypeID_NearestPlus1_5X}, +}; + static const GtkRadioActionEntry interpolation_entries[] = { - { "interp_nearest", NULL, "_Nearest", NULL, NULL, 0}, - { "interp_bilinear", NULL, "_Bilinear", NULL, NULL, 1}, + { "interp_nearest", NULL, "_Nearest", NULL, NULL, GDK_INTERP_NEAREST}, + { "interp_tiles", NULL, "_Tiles", NULL, NULL, GDK_INTERP_TILES}, + { "interp_bilinear", NULL, "_Bilinear", NULL, NULL, GDK_INTERP_BILINEAR}, + { "interp_hyper", NULL, "_Hyper", NULL, NULL, GDK_INTERP_HYPER}, }; static const GtkRadioActionEntry rotation_entries[] = { @@ -582,7 +632,7 @@ joinThread_gdb( void *thread_handle) { uint SPUMode = SPUMODE_DUALASYNC; uint Frameskip = 0; bool autoframeskip = false; -GdkInterpType Interpolation = GDK_INTERP_BILINEAR; +GdkInterpType Interpolation = GDK_INTERP_NEAREST; static GtkWidget *pWindow; static GtkWidget *pStatusBar; @@ -1094,6 +1144,7 @@ static void UpdateDrawingAreaAspect() } } + video.SetSourceSize(W, H); gtk_widget_set_size_request(GTK_WIDGET(pDrawingArea), W, H); } @@ -1125,7 +1176,7 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo } -static inline void gpu_screen_to_rgb(guchar * rgb, int size) +static inline void gpu_screen_to_rgb(guchar * rgb, int size, int pixelsize) { gint rot = nds_screen.rotation_angle; gint height, width; @@ -1135,7 +1186,6 @@ static inline void gpu_screen_to_rgb(guchar * rgb, int size) width = screen_size[nds_screen.orientation].width; height = screen_size[nds_screen.orientation].height; - memset(rgb, 0, size); for (gint i = 0; i < width; i++) { for (gint j = 0; j < height; j++) { gint row = j, col = i; @@ -1150,12 +1200,12 @@ static inline void gpu_screen_to_rgb(guchar * rgb, int size) gpu_pixel = *((u16 *) & GPU_screen[(col + row * 256) << 1]); if (rot == 0 || rot == 180) - offset = i * 3 + j * 3 * width; + offset = i * pixelsize + j * pixelsize * width; else - offset = j * 3 + (width - i - 1) * 3 * height; + offset = j * pixelsize + (width - i - 1) * pixelsize * height; if (rot == 90 || rot == 180) - offset = size - offset - 3; + offset = size - offset - pixelsize; *(rgb + offset + 0) = ((gpu_pixel >> 0) & 0x1f) << 3; *(rgb + offset + 1) = ((gpu_pixel >> 5) & 0x1f) << 3; @@ -1168,7 +1218,6 @@ static inline void gpu_screen_to_rgb(guchar * rgb, int size) static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpointer data) { GdkPixbuf *resizedPixbuf, *drawPixbuf; - guchar rgb[SCREENS_PIXEL_SIZE*SCREEN_BYTES_PER_PIXEL]; cairo_t *cr; GdkWindow *window; @@ -1242,16 +1291,28 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo osd->update(); DrawHUD(); - gpu_screen_to_rgb(rgb, imgW*imgH*SCREEN_BYTES_PER_PIXEL); - drawPixbuf = gdk_pixbuf_new_from_data(rgb, GDK_COLORSPACE_RGB, - FALSE, 8, imgW, imgH, imgW*SCREEN_BYTES_PER_PIXEL, NULL, NULL); - if ((hratio != 1.0) || (vratio != 1.0)) { - resizedPixbuf = gdk_pixbuf_scale_simple (drawPixbuf, hratio*imgW, vratio*imgH, - Interpolation); - g_object_unref(drawPixbuf); - drawPixbuf = resizedPixbuf; + gpu_screen_to_rgb((u8*)video.GetSrcBufferPtr(), imgW*imgH*4, 4); + + u32* fbuf = video.RunFilter(); + int dstW = video.GetDstWidth(); + int dstH = video.GetDstHeight(); + //Convert to 24-bit + guchar dsurf24[dstW*dstH*SCREEN_BYTES_PER_PIXEL]; + gint k=0; + for (gint i=0; iwindow); gdk_cairo_set_source_pixbuf(cr, drawPixbuf, 0, 0); @@ -1694,7 +1755,7 @@ static void Printscreen() H = screen_size[nds_screen.orientation].width; } - gpu_screen_to_rgb(rgb, W*H*SCREEN_BYTES_PER_PIXEL); + gpu_screen_to_rgb(rgb, W*H*SCREEN_BYTES_PER_PIXEL, 3); screenshot = gdk_pixbuf_new_from_data(rgb, GDK_COLORSPACE_RGB, FALSE, @@ -1775,10 +1836,15 @@ static void SelectFirmwareFile() } #endif +static void Modify_PriInterpolation(GtkAction *action, GtkRadioAction *current) +{ + uint filter = gtk_radio_action_get_current_value(current) ; + video.ChangeFilterByID((VideoFilterTypeID)filter); +} + static void Modify_Interpolation(GtkAction *action, GtkRadioAction *current) { - uint i = gtk_radio_action_get_current_value(current) ; - Interpolation = (i == 0 ? GDK_INTERP_NEAREST : GDK_INTERP_BILINEAR); + Interpolation = (GdkInterpType)gtk_radio_action_get_current_value(current); } static void Modify_SPUMode(GtkAction *action, GtkRadioAction *current) @@ -2219,7 +2285,9 @@ common_gtk_main( class configured_features *my_config) gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries), my_config->savetype, G_CALLBACK(changesavetype), NULL); gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries), - 1, G_CALLBACK(Modify_Interpolation), NULL); + GDK_INTERP_NEAREST, G_CALLBACK(Modify_Interpolation), NULL); + gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries), + VideoFilterTypeID_HQ2XS, G_CALLBACK(Modify_PriInterpolation), NULL); gtk_action_group_add_radio_actions(action_group, spumode_entries, G_N_ELEMENTS(spumode_entries), 0, G_CALLBACK(Modify_SPUMode), NULL); gtk_action_group_add_radio_actions(action_group, frameskip_entries, G_N_ELEMENTS(frameskip_entries), @@ -2349,6 +2417,12 @@ common_gtk_main( class configured_features *my_config) g_timeout_add_seconds(my_config->timeout, timeout_exit_cb, GINT_TO_POINTER(my_config->timeout)); } + /* Video filter parameters */ + video.SetFilterParameteri(VF_PARAM_SCANLINE_A, _scanline_filter_a); + video.SetFilterParameteri(VF_PARAM_SCANLINE_B, _scanline_filter_b); + video.SetFilterParameteri(VF_PARAM_SCANLINE_C, _scanline_filter_c); + video.SetFilterParameteri(VF_PARAM_SCANLINE_D, _scanline_filter_d); + /* Main loop */ gtk_main();