Linux (gtk):
- Remove gtk pixbuf usage on drawing DS screens, use only Cairo. - Use transformation matrix to handle touchscreen coordinates. - Adapt RGB555-to-RGBA8888 conversion code from Cocoa port, should result in brighter colour. - Re-enable fullscreen menu item on start.
This commit is contained in:
parent
4fec0a060e
commit
2fe8cb330d
|
@ -84,10 +84,7 @@
|
||||||
|
|
||||||
#define EMULOOP_PRIO (G_PRIORITY_HIGH_IDLE + 20 + 1)
|
#define EMULOOP_PRIO (G_PRIORITY_HIGH_IDLE + 20 + 1)
|
||||||
|
|
||||||
#define SCREENS_PIXEL_SIZE (256*192*2)
|
|
||||||
#define SCREEN_BYTES_PER_PIXEL 3
|
|
||||||
#define GAP_SIZE 64
|
#define GAP_SIZE 64
|
||||||
#define GAP_COLOR (0x000000)
|
|
||||||
|
|
||||||
static int gtk_fps_limiter_disabled;
|
static int gtk_fps_limiter_disabled;
|
||||||
static int draw_count;
|
static int draw_count;
|
||||||
|
@ -262,10 +259,11 @@ static const char *ui_description =
|
||||||
" <menuitem action='pri_interp_5xbrz'/>"
|
" <menuitem action='pri_interp_5xbrz'/>"
|
||||||
" </menu>"
|
" </menu>"
|
||||||
" <menu action='InterpolationMenu'>"
|
" <menu action='InterpolationMenu'>"
|
||||||
|
" <menuitem action='interp_fast'/>"
|
||||||
" <menuitem action='interp_nearest'/>"
|
" <menuitem action='interp_nearest'/>"
|
||||||
" <menuitem action='interp_tiles'/>"
|
" <menuitem action='interp_good'/>"
|
||||||
" <menuitem action='interp_bilinear'/>"
|
" <menuitem action='interp_bilinear'/>"
|
||||||
" <menuitem action='interp_hyper'/>"
|
" <menuitem action='interp_best'/>"
|
||||||
" </menu>"
|
" </menu>"
|
||||||
" <menu action='HudMenu'>"
|
" <menu action='HudMenu'>"
|
||||||
#ifdef HAVE_LIBAGG
|
#ifdef HAVE_LIBAGG
|
||||||
|
@ -392,8 +390,8 @@ static const GtkActionEntry action_entries[] = {
|
||||||
{ "RotationMenu", NULL, "_Rotation" },
|
{ "RotationMenu", NULL, "_Rotation" },
|
||||||
{ "OrientationMenu", NULL, "LCDs _Layout" },
|
{ "OrientationMenu", NULL, "LCDs _Layout" },
|
||||||
{ "WinsizeMenu", NULL, "_Window Size" },
|
{ "WinsizeMenu", NULL, "_Window Size" },
|
||||||
{ "PriInterpolationMenu", NULL, "Primary _Interpolation" },
|
{ "PriInterpolationMenu", NULL, "Video _Filter" },
|
||||||
{ "InterpolationMenu", NULL, "S_econdary Interpolation" },
|
{ "InterpolationMenu", NULL, "S_econdary Video Filter" },
|
||||||
{ "HudMenu", NULL, "_HUD" },
|
{ "HudMenu", NULL, "_HUD" },
|
||||||
#ifndef HAVE_LIBAGG
|
#ifndef HAVE_LIBAGG
|
||||||
{ "hud_notsupported", NULL, "HUD support not compiled" },
|
{ "hud_notsupported", NULL, "HUD support not compiled" },
|
||||||
|
@ -459,10 +457,11 @@ static const GtkRadioActionEntry pri_interpolation_entries[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GtkRadioActionEntry interpolation_entries[] = {
|
static const GtkRadioActionEntry interpolation_entries[] = {
|
||||||
{ "interp_nearest", NULL, "_Nearest", NULL, NULL, GDK_INTERP_NEAREST},
|
{ "interp_fast", NULL, "_Fast", NULL, NULL, CAIRO_FILTER_FAST },
|
||||||
{ "interp_tiles", NULL, "_Tiles", NULL, NULL, GDK_INTERP_TILES},
|
{ "interp_nearest", NULL, "_Nearest-neighbor", NULL, NULL, CAIRO_FILTER_NEAREST },
|
||||||
{ "interp_bilinear", NULL, "_Bilinear", NULL, NULL, GDK_INTERP_BILINEAR},
|
{ "interp_good", NULL, "_Good", NULL, NULL, CAIRO_FILTER_GOOD },
|
||||||
{ "interp_hyper", NULL, "_Hyper", NULL, NULL, GDK_INTERP_HYPER},
|
{ "interp_bilinear", NULL, "_Bilinear", NULL, NULL, CAIRO_FILTER_BILINEAR },
|
||||||
|
{ "interp_best", NULL, "B_est", NULL, NULL, CAIRO_FILTER_BEST },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GtkRadioActionEntry rotation_entries[] = {
|
static const GtkRadioActionEntry rotation_entries[] = {
|
||||||
|
@ -763,7 +762,7 @@ uint SPUMode = SPUMODE_DUALASYNC;
|
||||||
uint Frameskip = 0;
|
uint Frameskip = 0;
|
||||||
uint autoFrameskipMax = 0;
|
uint autoFrameskipMax = 0;
|
||||||
bool autoframeskip = true;
|
bool autoframeskip = true;
|
||||||
GdkInterpType Interpolation = GDK_INTERP_NEAREST;
|
cairo_filter_t Interpolation = CAIRO_FILTER_NEAREST;
|
||||||
|
|
||||||
static GtkWidget *pWindow;
|
static GtkWidget *pWindow;
|
||||||
static GtkWidget *pStatusBar;
|
static GtkWidget *pStatusBar;
|
||||||
|
@ -774,11 +773,8 @@ static GtkUIManager *ui_manager;
|
||||||
struct nds_screen_t {
|
struct nds_screen_t {
|
||||||
guint gap_size;
|
guint gap_size;
|
||||||
gint rotation_angle;
|
gint rotation_angle;
|
||||||
guint orientation;
|
orientation_enum orientation;
|
||||||
gint touch_x;
|
cairo_matrix_t touch_matrix;
|
||||||
gint touch_y;
|
|
||||||
gint touch_width;
|
|
||||||
gint touch_height;
|
|
||||||
gboolean swap;
|
gboolean swap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1412,9 +1408,6 @@ static void UpdateDrawingAreaAspect()
|
||||||
H = screen_size[nds_screen.orientation].width;
|
H = screen_size[nds_screen.orientation].width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The gap is added after filtering
|
|
||||||
video.SetSourceSize(W, H);
|
|
||||||
|
|
||||||
if (nds_screen.orientation != ORIENT_SINGLE) {
|
if (nds_screen.orientation != ORIENT_SINGLE) {
|
||||||
if (nds_screen.orientation == ORIENT_VERTICAL) {
|
if (nds_screen.orientation == ORIENT_VERTICAL) {
|
||||||
if ((nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180)) {
|
if ((nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180)) {
|
||||||
|
@ -1455,7 +1448,7 @@ static void SetWinsize(GtkAction *action, GtkRadioAction *current)
|
||||||
|
|
||||||
static void SetOrientation(GtkAction *action, GtkRadioAction *current)
|
static void SetOrientation(GtkAction *action, GtkRadioAction *current)
|
||||||
{
|
{
|
||||||
nds_screen.orientation = gtk_radio_action_get_current_value(current);
|
nds_screen.orientation = (orientation_enum)gtk_radio_action_get_current_value(current);
|
||||||
UpdateDrawingAreaAspect();
|
UpdateDrawingAreaAspect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,230 +1461,189 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adapted from Cocoa port
|
||||||
|
static const uint8_t bits5to8[] = {
|
||||||
|
0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3A,
|
||||||
|
0x42, 0x4A, 0x52, 0x5A, 0x63, 0x6B, 0x73, 0x7B,
|
||||||
|
0x84, 0x8C, 0x94, 0x9C, 0xA5, 0xAD, 0xB5, 0xBD,
|
||||||
|
0xC5, 0xCE, 0xD6, 0xDE, 0xE6, 0xEF, 0xF7, 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
static inline void gpu_screen_to_rgb(guchar * rgb, int size, int pixelsize)
|
static inline uint32_t RGB555ToRGBA8888(const uint16_t color16)
|
||||||
{
|
{
|
||||||
gint rot = nds_screen.rotation_angle;
|
return (bits5to8[((color16 >> 0) & 0x001F)] << 0) |
|
||||||
gint height, width;
|
(bits5to8[((color16 >> 5) & 0x001F)] << 8) |
|
||||||
u16 gpu_pixel;
|
(bits5to8[((color16 >> 10) & 0x001F)] << 16) |
|
||||||
u32 offset;
|
0xFF000000;
|
||||||
|
}
|
||||||
|
|
||||||
width = screen_size[nds_screen.orientation].width;
|
// Adapted from Cocoa port
|
||||||
height = screen_size[nds_screen.orientation].height;
|
static inline void RGB555ToRGBA8888Buffer(const uint16_t *__restrict__ srcBuffer, uint32_t *__restrict__ destBuffer, size_t pixelCount)
|
||||||
|
{
|
||||||
|
const uint32_t *__restrict__ destBufferEnd = destBuffer + pixelCount;
|
||||||
|
|
||||||
for (gint i = 0; i < width; i++) {
|
while (destBuffer < destBufferEnd)
|
||||||
for (gint j = 0; j < height; j++) {
|
{
|
||||||
gint row = j, col = i;
|
*destBuffer++ = RGB555ToRGBA8888(*srcBuffer++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (i >= 256) {
|
static inline void gpu_screen_to_rgb(u32* dst)
|
||||||
col = i - 256;
|
{
|
||||||
row = j + 192;
|
RGB555ToRGBA8888Buffer((u16*)GPU_screen, dst, 256 * 384);
|
||||||
}
|
}
|
||||||
if (nds_screen.swap)
|
|
||||||
row = (row + 192) % 384;
|
|
||||||
|
|
||||||
gpu_pixel = *((u16 *) & GPU_screen[(col + row * 256) << 1]);
|
static inline void drawScreen(cairo_t* cr, u32* buf, gint w, gint h) {
|
||||||
|
cairo_surface_t* surf = cairo_image_surface_create_for_data((u8*)buf, CAIRO_FORMAT_RGB24, w, h, w * 4);
|
||||||
|
cairo_set_source_surface(cr, surf, 0, 0);
|
||||||
|
cairo_pattern_set_filter(cairo_get_source(cr), Interpolation);
|
||||||
|
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD);
|
||||||
|
cairo_rectangle(cr, 0, 0, w, h);
|
||||||
|
cairo_fill(cr);
|
||||||
|
cairo_surface_destroy(surf);
|
||||||
|
}
|
||||||
|
|
||||||
if (rot == 0 || rot == 180)
|
static inline void drawTopScreen(cairo_t* cr, u32* buf, gint w, gint h, gint gap, gint rotation_angle, bool swap, orientation_enum orientation) {
|
||||||
offset = i * pixelsize + j * pixelsize * width;
|
if (orientation == ORIENT_SINGLE && swap) {
|
||||||
else
|
return;
|
||||||
offset = j * pixelsize + (width - i - 1) * pixelsize * height;
|
}
|
||||||
|
cairo_save(cr);
|
||||||
|
switch (orientation) {
|
||||||
|
case ORIENT_VERTICAL:
|
||||||
|
if (swap) {
|
||||||
|
cairo_translate(cr, 0, h + gap);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ORIENT_HORIZONTAL:
|
||||||
|
if (swap) {
|
||||||
|
cairo_translate(cr, w, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drawScreen(cr, buf, w, h);
|
||||||
|
cairo_restore(cr);
|
||||||
|
}
|
||||||
|
|
||||||
if (rot == 90 || rot == 180)
|
static inline void drawBottomScreen(cairo_t* cr, u32* buf, gint w, gint h, gint gap, gint rotation_angle, bool swap, orientation_enum orientation) {
|
||||||
offset = size - offset - pixelsize;
|
if (orientation == ORIENT_SINGLE && !swap) {
|
||||||
|
return;
|
||||||
*(rgb + offset + 0) = ((gpu_pixel >> 0) & 0x1f) << 3;
|
}
|
||||||
*(rgb + offset + 1) = ((gpu_pixel >> 5) & 0x1f) << 3;
|
cairo_save(cr);
|
||||||
*(rgb + offset + 2) = ((gpu_pixel >> 10) & 0x1f) << 3;
|
switch (orientation) {
|
||||||
}
|
case ORIENT_VERTICAL:
|
||||||
}
|
if (!swap) {
|
||||||
|
cairo_translate(cr, 0, h + gap);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ORIENT_HORIZONTAL:
|
||||||
|
if (!swap) {
|
||||||
|
cairo_translate(cr, w, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Store the inverted matrix for converting touchscreen coordinates
|
||||||
|
cairo_get_matrix(cr, &nds_screen.touch_matrix);
|
||||||
|
drawScreen(cr, buf, w, h);
|
||||||
|
cairo_restore(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drawing callback */
|
/* Drawing callback */
|
||||||
static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
||||||
{
|
{
|
||||||
GdkPixbuf *resizedPixbuf, *drawPixbuf;
|
GdkWindow* window = gtk_widget_get_window(widget);
|
||||||
cairo_t *cr;
|
gint daW, daH;
|
||||||
GdkWindow *window;
|
|
||||||
|
|
||||||
gfloat vratio, hratio, nscreen_ratio;
|
|
||||||
gint daW, daH, imgW, imgH, screenW, screenH, gapW, gapH;
|
|
||||||
gint primaryOffsetX, primaryOffsetY, secondaryOffsetX, secondaryOffsetY;
|
|
||||||
const gboolean gap_vertical = ((nds_screen.orientation == ORIENT_VERTICAL) ^ (nds_screen.rotation_angle == 90 || nds_screen.rotation_angle == 270));
|
|
||||||
|
|
||||||
window = gtk_widget_get_window(GTK_WIDGET(pDrawingArea));
|
|
||||||
#if GTK_CHECK_VERSION(2,24,0)
|
#if GTK_CHECK_VERSION(2,24,0)
|
||||||
daW = gdk_window_get_width(window);
|
daW = gdk_window_get_width(window);
|
||||||
daH = gdk_window_get_height(window);
|
daH = gdk_window_get_height(window);
|
||||||
#else
|
#else
|
||||||
gdk_drawable_get_size(window, &daW, &daH);
|
gdk_drawable_get_size(window, &daW, &daH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
#ifdef HAVE_LIBAGG
|
||||||
imgW = screen_size[nds_screen.orientation].width;
|
osd->update();
|
||||||
imgH = screen_size[nds_screen.orientation].height;
|
DrawHUD();
|
||||||
} else {
|
osd->clear();
|
||||||
imgH = screen_size[nds_screen.orientation].width;
|
#endif
|
||||||
imgW = screen_size[nds_screen.orientation].height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds_screen.orientation != ORIENT_VERTICAL) {
|
gpu_screen_to_rgb(video.GetSrcBufferPtr());
|
||||||
gapH = 0;
|
|
||||||
gapW = 0;
|
|
||||||
} else if (gap_vertical) {
|
|
||||||
gapH = nds_screen.gap_size;
|
|
||||||
gapW = 0;
|
|
||||||
} else {
|
|
||||||
gapH = 0;
|
|
||||||
gapW = nds_screen.gap_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
hratio = (float)daW / (float)(imgW + gapW);
|
u32* fbuf = video.RunFilter();
|
||||||
vratio = (float)daH / (float)(imgH + gapH);
|
gint dstW = video.GetDstWidth();
|
||||||
hratio = MIN(hratio, vratio);
|
gint dstH = video.GetDstHeight();
|
||||||
vratio = hratio;
|
// Convert from RGBA to BGRX
|
||||||
|
CACHE_ALIGN u32 conv_buf[dstW * dstH];
|
||||||
|
for (u32 *p = conv_buf, *pe = conv_buf + dstW * dstH; p < pe; p++)
|
||||||
|
{
|
||||||
|
*p = __builtin_bswap32(*fbuf++) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
primaryOffsetX = (daW-(int)(hratio*(float)(imgW+gapW)))/2;
|
gint dstScale = dstW * 2 / 256; // Actual scale * 2 to handle 1.5x filters
|
||||||
primaryOffsetY = (daH-(int)(vratio*(float)(imgH+gapH)))/2;
|
|
||||||
|
|
||||||
nscreen_ratio = nds_screen.orientation == ORIENT_SINGLE ? 1 : 0.5;
|
gint gap = nds_screen.orientation == ORIENT_VERTICAL ? nds_screen.gap_size * dstScale / 2 : 0;
|
||||||
if (gap_vertical) {
|
gint imgW, imgH;
|
||||||
screenW = (int)(hratio*(float)(imgW));
|
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
||||||
screenH = (int)(vratio*(float)(imgH)*nscreen_ratio);
|
imgW = screen_size[nds_screen.orientation].width * dstScale / 2;
|
||||||
secondaryOffsetX = primaryOffsetX;
|
imgH = screen_size[nds_screen.orientation].height * dstScale / 2 + gap;
|
||||||
secondaryOffsetY = primaryOffsetY + screenH + (int)(vratio * (float)gapH);
|
} else {
|
||||||
} else {
|
imgH = screen_size[nds_screen.orientation].width * dstScale / 2;
|
||||||
screenW = (int)(hratio*(float)(imgW)*nscreen_ratio);
|
imgW = screen_size[nds_screen.orientation].height * dstScale / 2 + gap;
|
||||||
screenH = (int)(vratio*(float)(imgH));
|
}
|
||||||
secondaryOffsetX = primaryOffsetX + screenW + (int)(hratio * (float)gapW);
|
|
||||||
secondaryOffsetY = primaryOffsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((nds_screen.swap) ^
|
// Calculate scale to fit display area to window
|
||||||
((nds_screen.orientation == ORIENT_VERTICAL && (nds_screen.rotation_angle == 90 || nds_screen.rotation_angle == 180)) ||
|
gfloat hratio = (gfloat)daW / (gfloat)imgW;
|
||||||
(nds_screen.orientation == ORIENT_HORIZONTAL && (nds_screen.rotation_angle == 180 || nds_screen.rotation_angle == 270)))) {
|
gfloat vratio = (gfloat)daH / (gfloat)imgH;
|
||||||
nds_screen.touch_x = primaryOffsetX;
|
hratio = MIN(hratio, vratio);
|
||||||
nds_screen.touch_y = primaryOffsetY;
|
vratio = hratio;
|
||||||
} else if (nds_screen.orientation != ORIENT_SINGLE) {
|
|
||||||
nds_screen.touch_x = secondaryOffsetX;
|
|
||||||
nds_screen.touch_y = secondaryOffsetY;
|
|
||||||
} else {
|
|
||||||
nds_screen.touch_x = -1;
|
|
||||||
nds_screen.touch_y = -1;
|
|
||||||
}
|
|
||||||
nds_screen.touch_width = screenW;
|
|
||||||
nds_screen.touch_height = screenH;
|
|
||||||
|
|
||||||
osd->update();
|
cairo_t* cr = gdk_cairo_create(window);
|
||||||
DrawHUD();
|
|
||||||
|
|
||||||
gpu_screen_to_rgb((u8*)video.GetSrcBufferPtr(), imgW*imgH*4, 4);
|
// Scale to window size at center of area
|
||||||
|
cairo_translate(cr, daW / 2, daH / 2);
|
||||||
|
cairo_scale(cr, hratio, vratio);
|
||||||
|
// Rotate area
|
||||||
|
cairo_rotate(cr, M_PI / 180 * nds_screen.rotation_angle);
|
||||||
|
// Translate area to top-left corner
|
||||||
|
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
||||||
|
cairo_translate(cr, -imgW / 2, -imgH / 2);
|
||||||
|
} else {
|
||||||
|
cairo_translate(cr, -imgH / 2, -imgW / 2);
|
||||||
|
}
|
||||||
|
// Draw both screens
|
||||||
|
drawTopScreen(cr, conv_buf, dstW, dstH / 2, gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation);
|
||||||
|
drawBottomScreen(cr, conv_buf + dstW * dstH / 2, dstW, dstH / 2, gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation);
|
||||||
|
// Draw gap
|
||||||
|
cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
|
||||||
|
cairo_rectangle(cr, 0, dstH / 2, dstW, gap);
|
||||||
|
cairo_fill(cr);
|
||||||
|
// Correct the touchscreen matrix
|
||||||
|
cairo_matrix_scale(&nds_screen.touch_matrix, (double)dstScale / 2, (double)dstScale / 2);
|
||||||
|
cairo_matrix_invert(&nds_screen.touch_matrix);
|
||||||
|
|
||||||
u32* fbuf = video.RunFilter();
|
cairo_destroy(cr);
|
||||||
int dstW = video.GetDstWidth();
|
draw_count++;
|
||||||
int dstH = video.GetDstHeight();
|
|
||||||
int dstScale = (dstH / imgH); // Assumed to be integer
|
|
||||||
int dstGapH = gapH * dstScale;
|
|
||||||
int dstGapW = gapW * dstScale;
|
|
||||||
//Convert to 24-bit
|
|
||||||
guchar dsurf24[(dstW+dstGapW)*(dstH+dstGapH)*SCREEN_BYTES_PER_PIXEL];
|
|
||||||
gint i=0, k=0, x, y;
|
|
||||||
// Top half
|
|
||||||
for (x = 0; x < dstH / 2; x++) {
|
|
||||||
// Left half
|
|
||||||
for (y = 0; y < dstW / 2; y++, i++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = fbuf[i];
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
// Vertical gap
|
|
||||||
for(y = 0; y < dstGapW; y++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = GAP_COLOR;
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
// Right half
|
|
||||||
for (y = 0; y < dstW / 2; y++, i++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = fbuf[i];
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Horizontal gap
|
|
||||||
for (x = 0; x < dstGapH; x++) {
|
|
||||||
for(y = 0; y < dstW + dstGapW; y++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = GAP_COLOR;
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Bottom half
|
|
||||||
for (x = 0; x < dstH / 2; x++) {
|
|
||||||
// Left half
|
|
||||||
for (y = 0; y < dstW / 2; y++, i++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = fbuf[i];
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
// Mid gap
|
|
||||||
for(y = 0; y < dstGapW; y++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = GAP_COLOR;
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
// Right half
|
|
||||||
for (y = 0; y < dstW / 2; y++, i++) {
|
|
||||||
*(u32*) &(dsurf24[k]) = fbuf[i];
|
|
||||||
k += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawPixbuf = gdk_pixbuf_new_from_data(dsurf24, GDK_COLORSPACE_RGB,
|
return TRUE;
|
||||||
FALSE, 8, dstW + dstGapW, dstH + dstGapH, (dstW + dstGapW) * SCREEN_BYTES_PER_PIXEL, NULL, NULL);
|
|
||||||
|
|
||||||
resizedPixbuf = gdk_pixbuf_scale_simple(drawPixbuf, hratio*(imgW+gapW), vratio*(imgH+gapH),
|
|
||||||
Interpolation);
|
|
||||||
g_object_unref(drawPixbuf);
|
|
||||||
drawPixbuf = resizedPixbuf;
|
|
||||||
|
|
||||||
cr = gdk_cairo_create(widget->window);
|
|
||||||
gdk_cairo_set_source_pixbuf(cr, drawPixbuf, 0, 0);
|
|
||||||
|
|
||||||
if (nds_screen.orientation != ORIENT_SINGLE) {
|
|
||||||
gdk_cairo_set_source_pixbuf(cr, drawPixbuf, primaryOffsetX, primaryOffsetY);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref(drawPixbuf); //drawPixbuf was never unref'd, so its ref count stayed above 0 and it was never freed
|
|
||||||
|
|
||||||
cairo_paint(cr);
|
|
||||||
cairo_destroy(cr);
|
|
||||||
draw_count++;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////// KEYS AND STYLUS UPDATE ///////////////////////////////////////
|
/////////////////////////////// KEYS AND STYLUS UPDATE ///////////////////////////////////////
|
||||||
|
|
||||||
static gboolean rotoscaled_touchpos(gint x, gint y, gboolean start)
|
static gboolean rotoscaled_touchpos(gint x, gint y, gboolean start)
|
||||||
{
|
{
|
||||||
|
double devX, devY;
|
||||||
u16 EmuX, EmuY;
|
u16 EmuX, EmuY;
|
||||||
gint X, Y;
|
gint X, Y;
|
||||||
|
|
||||||
if (nds_screen.touch_x == -1 || nds_screen.touch_y == -1) {
|
if (nds_screen.orientation == ORIENT_SINGLE && !nds_screen.swap) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
devX = x;
|
||||||
X = (x - nds_screen.touch_x) * 256 / nds_screen.touch_width;
|
devY = y;
|
||||||
Y = (y - nds_screen.touch_y) * 192 / nds_screen.touch_height;
|
cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY);
|
||||||
} else {
|
X = devX;
|
||||||
X = (y - nds_screen.touch_y) * 256 / nds_screen.touch_height;
|
Y = devY;
|
||||||
Y = (x - nds_screen.touch_x) * 192 / nds_screen.touch_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds_screen.rotation_angle == 180 || nds_screen.rotation_angle == 270) {
|
LOG("X=%d, Y=%d\n", X, Y);
|
||||||
X = 255 - X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds_screen.rotation_angle == 90 || nds_screen.rotation_angle == 180) {
|
|
||||||
Y = 191 - Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG("X=%d, Y=%d\n",x,y);
|
|
||||||
|
|
||||||
if (!start || (X >= 0 && Y >= 0 && X < 256 && Y < 192)) {
|
if (!start || (X >= 0 && Y >= 0 && X < 256 && Y < 192)) {
|
||||||
EmuX = CLAMP(X, 0, 255);
|
EmuX = CLAMP(X, 0, 255);
|
||||||
|
@ -2073,13 +2025,13 @@ static void Printscreen()
|
||||||
GdkPixbuf *screenshot;
|
GdkPixbuf *screenshot;
|
||||||
gchar *filename, *filen;
|
gchar *filename, *filen;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
u8 *rgb;
|
u8 rgb[256 * 384 * 4];
|
||||||
static int seq = 0;
|
static int seq = 0;
|
||||||
gint H, W;
|
gint H, W;
|
||||||
|
|
||||||
rgb = (u8 *) malloc(SCREENS_PIXEL_SIZE*SCREEN_BYTES_PER_PIXEL);
|
//rgb = (u8 *) malloc(SCREENS_PIXEL_SIZE*SCREEN_BYTES_PER_PIXEL);
|
||||||
if (!rgb)
|
//if (!rgb)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) {
|
||||||
W = screen_size[nds_screen.orientation].width;
|
W = screen_size[nds_screen.orientation].width;
|
||||||
|
@ -2089,14 +2041,14 @@ static void Printscreen()
|
||||||
H = screen_size[nds_screen.orientation].width;
|
H = screen_size[nds_screen.orientation].width;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu_screen_to_rgb(rgb, W*H*SCREEN_BYTES_PER_PIXEL, 3);
|
gpu_screen_to_rgb((u32*)rgb);
|
||||||
screenshot = gdk_pixbuf_new_from_data(rgb,
|
screenshot = gdk_pixbuf_new_from_data(rgb,
|
||||||
GDK_COLORSPACE_RGB,
|
GDK_COLORSPACE_RGB,
|
||||||
FALSE,
|
TRUE,
|
||||||
8,
|
8,
|
||||||
W,
|
W,
|
||||||
H,
|
H,
|
||||||
W*SCREEN_BYTES_PER_PIXEL,
|
W * 4,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
@ -2111,7 +2063,7 @@ static void Printscreen()
|
||||||
seq++;
|
seq++;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rgb);
|
//free(rgb);
|
||||||
g_object_unref(screenshot);
|
g_object_unref(screenshot);
|
||||||
g_free(filename);
|
g_free(filename);
|
||||||
g_free(filen);
|
g_free(filen);
|
||||||
|
@ -2178,7 +2130,7 @@ static void Modify_PriInterpolation(GtkAction *action, GtkRadioAction *current)
|
||||||
|
|
||||||
static void Modify_Interpolation(GtkAction *action, GtkRadioAction *current)
|
static void Modify_Interpolation(GtkAction *action, GtkRadioAction *current)
|
||||||
{
|
{
|
||||||
Interpolation = (GdkInterpType)gtk_radio_action_get_current_value(current);
|
Interpolation = (cairo_filter_t)gtk_radio_action_get_current_value(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Modify_SPUMode(GtkAction *action, GtkRadioAction *current)
|
static void Modify_SPUMode(GtkAction *action, GtkRadioAction *current)
|
||||||
|
@ -2379,7 +2331,6 @@ gboolean EmuLoop(gpointer data)
|
||||||
|
|
||||||
_updateDTools();
|
_updateDTools();
|
||||||
gtk_widget_queue_draw( pDrawingArea );
|
gtk_widget_queue_draw( pDrawingArea );
|
||||||
osd->clear();
|
|
||||||
avout_x264.updateVideo((u16*)GPU_screen);
|
avout_x264.updateVideo((u16*)GPU_screen);
|
||||||
|
|
||||||
if (gtk_fps_limiter_disabled || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
|
if (gtk_fps_limiter_disabled || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
|
||||||
|
@ -2890,7 +2841,7 @@ common_gtk_main( class configured_features *my_config)
|
||||||
gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries),
|
gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries),
|
||||||
my_config->savetype, G_CALLBACK(changesavetype), NULL);
|
my_config->savetype, G_CALLBACK(changesavetype), NULL);
|
||||||
gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries),
|
gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries),
|
||||||
GDK_INTERP_NEAREST, G_CALLBACK(Modify_Interpolation), NULL);
|
Interpolation, G_CALLBACK(Modify_Interpolation), NULL);
|
||||||
gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries),
|
gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries),
|
||||||
VideoFilterTypeID_None, G_CALLBACK(Modify_PriInterpolation), NULL);
|
VideoFilterTypeID_None, G_CALLBACK(Modify_PriInterpolation), NULL);
|
||||||
gtk_action_group_add_radio_actions(action_group, spumode_entries, G_N_ELEMENTS(spumode_entries),
|
gtk_action_group_add_radio_actions(action_group, spumode_entries, G_N_ELEMENTS(spumode_entries),
|
||||||
|
@ -2916,7 +2867,6 @@ common_gtk_main( class configured_features *my_config)
|
||||||
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "printscreen"), FALSE);
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "printscreen"), FALSE);
|
||||||
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatlist"), FALSE);
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatlist"), FALSE);
|
||||||
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatsearch"), FALSE);
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatsearch"), FALSE);
|
||||||
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "fullscreen"), FALSE);
|
|
||||||
|
|
||||||
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
|
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue