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();