diff --git a/gfx/rpi.c b/gfx/rpi.c
index b718428c8e..19ea060323 100644
--- a/gfx/rpi.c
+++ b/gfx/rpi.c
@@ -1,435 +1,435 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
- * Copyright (C) 2012 - Michael Lelli
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "../libretro.h"
-#include "../general.h"
-#include "../input/linuxraw_input.h"
-#include "../driver.h"
-
-#ifdef HAVE_FREETYPE
-#include "fonts/fonts.h"
-#include "../file.h"
-#endif
-
-
-typedef struct {
- EGLDisplay mDisplay;
- EGLSurface mSurface;
- EGLContext mContext;
- uint32_t mScreenWidth;
- uint32_t mScreenHeight;
- float mScreenAspect;
- bool mKeepAspect;
- unsigned mTextureWidth;
- unsigned mTextureHeight;
- unsigned mRenderWidth;
- unsigned mRenderHeight;
- unsigned x1, y1, x2, y2;
- VGImageFormat mTexType;
- VGImage mImage;
- VGfloat mTransformMatrix[9];
- VGint scissor[4];
-
-#ifdef HAVE_FREETYPE
- char *mLastMsg;
- uint32_t mFontHeight;
- VGFont mFont;
- font_renderer_t *mFontRenderer;
- bool mFontsOn;
- VGuint mMsgLength;
- VGuint mGlyphIndices[1024];
- VGPaint mPaintFg;
- VGPaint mPaintBg;
-#endif
-} rpi_t;
-
-static volatile sig_atomic_t rpi_shutdown = 0;
-
-static void rpi_kill(int sig)
-{
- (void)sig;
- rpi_shutdown = 1;
-}
-
-static void rpi_set_nonblock_state(void *data, bool state)
-{
- rpi_t *rpi = (rpi_t*)data;
- eglSwapInterval(rpi->mDisplay, state ? 0 : 1);
-}
-
-static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data)
-{
- int32_t success;
- EGLBoolean result;
- EGLint num_config;
- rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t));
- *input = NULL;
-
- static EGL_DISPMANX_WINDOW_T nativewindow;
-
- DISPMANX_ELEMENT_HANDLE_T dispman_element;
- DISPMANX_DISPLAY_HANDLE_T dispman_display;
- DISPMANX_UPDATE_HANDLE_T dispman_update;
- DISPMANX_MODEINFO_T dispman_modeinfo;
- VC_RECT_T dst_rect;
- VC_RECT_T src_rect;
-
- static const EGLint attribute_list[] =
- {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_NONE
- };
-
- EGLConfig config;
-
- bcm_host_init();
-
- // get an EGL display connection
- rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY);
-
- // initialize the EGL display connection
- result = eglInitialize(rpi->mDisplay, NULL, NULL);
- rarch_assert(result != EGL_FALSE);
- eglBindAPI(EGL_OPENVG_API);
-
- // get an appropriate EGL frame buffer configuration
- result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config);
- rarch_assert(result != EGL_FALSE);
-
- // create an EGL rendering context
- rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL);
- rarch_assert(rpi->mContext != EGL_NO_CONTEXT);
-
- // create an EGL window surface
- success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight);
- rarch_assert(success >= 0);
-
- dst_rect.x = 0;
- dst_rect.y = 0;
- dst_rect.width = rpi->mScreenWidth;
- dst_rect.height = rpi->mScreenHeight;
-
- src_rect.x = 0;
- src_rect.y = 0;
- src_rect.width = rpi->mScreenWidth << 16;
- src_rect.height = rpi->mScreenHeight << 16;
-
- dispman_display = vc_dispmanx_display_open(0 /* LCD */);
- vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo);
- dispman_update = vc_dispmanx_update_start(0);
-
- dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
- 0/*layer*/, &dst_rect, 0/*src*/,
- &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE);
-
- nativewindow.element = dispman_element;
- nativewindow.width = rpi->mScreenWidth;
- nativewindow.height = rpi->mScreenHeight;
- vc_dispmanx_update_submit_sync(dispman_update);
-
- rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL);
- rarch_assert(rpi->mSurface != EGL_NO_SURFACE);
-
- // connect the context to the surface
- result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext);
- rarch_assert(result != EGL_FALSE);
-
- rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555;
- rpi->mKeepAspect = video->force_aspect;
-
- // check for SD televisions: they should always be 4:3
- if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576))
- rpi->mScreenAspect = 4.0f / 3.0f;
- else
- rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height;
-
- VGfloat clearColor[4] = {0, 0, 0, 1};
- vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
-
- rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE;
- // We can't use the native format because there's no sXRGB_1555 type and
- // emulation cores can send 0 in the top bit. We lose some speed on
- // conversion but I doubt it has any real affect, since we are only drawing
- // one image at the end of the day. Still keep the alpha channel for ABGR.
- rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED);
- rpi_set_nonblock_state(rpi, !video->vsync);
-
- linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init();
- if (linuxraw_input)
- {
- *input = (const input_driver_t *)&input_linuxraw;
- *input_data = linuxraw_input;
- }
-
-#ifdef HAVE_FREETYPE
- if (g_settings.video.font_enable)
- {
- rpi->mFont = vgCreateFont(0);
- rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f);
-
- const char *path = g_settings.video.font_path;
- if (!*path || !path_file_exists(path))
- path = font_renderer_get_default_font();
-
- rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight);
-
- if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer)
- {
- rpi->mFontsOn = true;
-
- rpi->mPaintFg = vgCreatePaint();
- rpi->mPaintBg = vgCreatePaint();
- VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f };
- VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f };
-
- vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg);
-
- vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg);
- }
- }
-#endif
-
- struct sigaction sa;
- sa.sa_handler = rpi_kill;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
-
- return rpi;
-}
-
-static void rpi_free(void *data)
-{
- rpi_t *rpi = (rpi_t*)data;
-
- vgDestroyImage(rpi->mImage);
-
-#ifdef HAVE_FREETYPE
- if (rpi->mFontsOn)
- {
- vgDestroyFont(rpi->mFont);
- font_renderer_free(rpi->mFontRenderer);
- vgDestroyPaint(rpi->mPaintFg);
- vgDestroyPaint(rpi->mPaintBg);
- }
-#endif
-
- // Release EGL resources
- eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(rpi->mDisplay, rpi->mSurface);
- eglDestroyContext(rpi->mDisplay, rpi->mContext);
- eglTerminate(rpi->mDisplay);
-
- free(rpi);
-}
-
-#ifdef HAVE_FREETYPE
-
-static void rpi_render_message(rpi_t *rpi, const char *msg)
-{
- free(rpi->mLastMsg);
- rpi->mLastMsg = strdup(msg);
-
- if(rpi->mMsgLength)
- {
- while (--rpi->mMsgLength)
- vgClearGlyph(rpi->mFont, rpi->mMsgLength);
-
- vgClearGlyph(rpi->mFont, 0);
- }
-
- struct font_output_list out;
- font_renderer_msg(rpi->mFontRenderer, msg, &out);
- struct font_output *head = out.head;
-
- while (head)
- {
- if (rpi->mMsgLength >= 1024)
- break;
-
- VGfloat origin[2], escapement[2];
- VGImage img;
-
- escapement[0] = (VGfloat) (head->advance_x);
- escapement[1] = (VGfloat) (head->advance_y);
- origin[0] = (VGfloat) (-head->char_off_x);
- origin[1] = (VGfloat) (head->char_off_y);
-
- img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED);
-
- // flip it
- for (unsigned i = 0; i < head->height; i++)
- vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1);
-
- vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement);
- vgDestroyImage(img);
-
- rpi->mMsgLength++;
- head = head->next;
- }
-
- font_renderer_free_output(&out);
-
- for (unsigned i = 0; i < rpi->mMsgLength; i++)
- rpi->mGlyphIndices[i] = i;
-}
-
-static void rpi_draw_message(rpi_t *rpi, const char *msg)
-{
- if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg))
- rpi_render_message(rpi, msg);
-
- vgSeti(VG_SCISSORING, VG_FALSE);
- vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
-
- VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f };
- vgSetfv(VG_GLYPH_ORIGIN, 2, origins);
- vgSetPaint(rpi->mPaintBg, VG_FILL_PATH);
- vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE);
- origins[0] += 2.0f;
- origins[1] += 2.0f;
- vgSetfv(VG_GLYPH_ORIGIN, 2, origins);
- vgSetPaint(rpi->mPaintFg, VG_FILL_PATH);
- vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE);
-
- vgSeti(VG_SCISSORING, VG_TRUE);
- vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
-}
-
-#endif
-
-static void rpi_calculate_quad(rpi_t *rpi)
-{
- // set viewport for aspect ratio, taken from the OpenGL driver
- if (rpi->mKeepAspect)
- {
- float desired_aspect = g_settings.video.aspect_ratio;
-
- // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
- // assume they are actually equal.
- if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001)
- {
- rpi->x1 = 0;
- rpi->y1 = 0;
- rpi->x2 = rpi->mScreenWidth;
- rpi->y2 = rpi->mScreenHeight;
- }
- else if (rpi->mScreenAspect > desired_aspect)
- {
- float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5;
- rpi->x1 = rpi->mScreenWidth * (0.5 - delta);
- rpi->y1 = 0;
- rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1;
- rpi->y2 = rpi->mScreenHeight + rpi->y1;
- }
- else
- {
- float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5;
- rpi->x1 = 0;
- rpi->y1 = rpi->mScreenHeight * (0.5 - delta);
- rpi->x2 = rpi->mScreenWidth + rpi->x1;
- rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1;
- }
- }
- else
- {
- rpi->x1 = 0;
- rpi->y1 = 0;
- rpi->x2 = rpi->mScreenWidth;
- rpi->y2 = rpi->mScreenHeight;
- }
-
- rpi->scissor[0] = rpi->x1;
- rpi->scissor[1] = rpi->y1;
- rpi->scissor[2] = rpi->x2 - rpi->x1;
- rpi->scissor[3] = rpi->y2 - rpi->y1;
-
- vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor);
-}
-
-static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
-{
- rpi_t *rpi = (rpi_t*)data;
-
- if (width != rpi->mRenderWidth || height != rpi->mRenderHeight)
- {
- rpi->mRenderWidth = width;
- rpi->mRenderHeight = height;
- rpi_calculate_quad(rpi);
- vguComputeWarpQuadToQuad(
- rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2,
- // needs to be flipped, Khronos loves their bottom-left origin
- 0, height, width, height, width, 0, 0, 0,
- rpi->mTransformMatrix);
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(rpi->mTransformMatrix);
- }
- vgSeti(VG_SCISSORING, VG_FALSE);
- vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight);
- vgSeti(VG_SCISSORING, VG_TRUE);
-
- vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height);
- vgDrawImage(rpi->mImage);
-
-#ifdef HAVE_FREETYPE
- if (msg && rpi->mFontsOn)
- rpi_draw_message(rpi, msg);
-#else
- (void)msg;
-#endif
-
- eglSwapBuffers(rpi->mDisplay, rpi->mSurface);
-
- return true;
-}
-
-static bool rpi_alive(void *data)
-{
- (void)data;
- return !rpi_shutdown;
-}
-
-static bool rpi_focus(void *data)
-{
- (void)data;
- return true;
-}
-
-const video_driver_t video_rpi = {
- rpi_init,
- rpi_frame,
- rpi_set_nonblock_state,
- rpi_alive,
- rpi_focus,
- NULL,
- rpi_free,
- "rpi"
-};
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
+ * Copyright (C) 2012 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "../libretro.h"
+#include "../general.h"
+#include "../input/linuxraw_input.h"
+#include "../driver.h"
+
+#ifdef HAVE_FREETYPE
+#include "fonts/fonts.h"
+#include "../file.h"
+#endif
+
+
+typedef struct {
+ EGLDisplay mDisplay;
+ EGLSurface mSurface;
+ EGLContext mContext;
+ uint32_t mScreenWidth;
+ uint32_t mScreenHeight;
+ float mScreenAspect;
+ bool mKeepAspect;
+ unsigned mTextureWidth;
+ unsigned mTextureHeight;
+ unsigned mRenderWidth;
+ unsigned mRenderHeight;
+ unsigned x1, y1, x2, y2;
+ VGImageFormat mTexType;
+ VGImage mImage;
+ VGfloat mTransformMatrix[9];
+ VGint scissor[4];
+
+#ifdef HAVE_FREETYPE
+ char *mLastMsg;
+ uint32_t mFontHeight;
+ VGFont mFont;
+ font_renderer_t *mFontRenderer;
+ bool mFontsOn;
+ VGuint mMsgLength;
+ VGuint mGlyphIndices[1024];
+ VGPaint mPaintFg;
+ VGPaint mPaintBg;
+#endif
+} rpi_t;
+
+static volatile sig_atomic_t rpi_shutdown = 0;
+
+static void rpi_kill(int sig)
+{
+ (void)sig;
+ rpi_shutdown = 1;
+}
+
+static void rpi_set_nonblock_state(void *data, bool state)
+{
+ rpi_t *rpi = (rpi_t*)data;
+ eglSwapInterval(rpi->mDisplay, state ? 0 : 1);
+}
+
+static void *rpi_init(const video_info_t *video, const input_driver_t **input, void **input_data)
+{
+ int32_t success;
+ EGLBoolean result;
+ EGLint num_config;
+ rpi_t *rpi = (rpi_t*)calloc(1, sizeof(rpi_t));
+ *input = NULL;
+
+ static EGL_DISPMANX_WINDOW_T nativewindow;
+
+ DISPMANX_ELEMENT_HANDLE_T dispman_element;
+ DISPMANX_DISPLAY_HANDLE_T dispman_display;
+ DISPMANX_UPDATE_HANDLE_T dispman_update;
+ DISPMANX_MODEINFO_T dispman_modeinfo;
+ VC_RECT_T dst_rect;
+ VC_RECT_T src_rect;
+
+ static const EGLint attribute_list[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ EGLConfig config;
+
+ bcm_host_init();
+
+ // get an EGL display connection
+ rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ rarch_assert(rpi->mDisplay != EGL_NO_DISPLAY);
+
+ // initialize the EGL display connection
+ result = eglInitialize(rpi->mDisplay, NULL, NULL);
+ rarch_assert(result != EGL_FALSE);
+ eglBindAPI(EGL_OPENVG_API);
+
+ // get an appropriate EGL frame buffer configuration
+ result = eglChooseConfig(rpi->mDisplay, attribute_list, &config, 1, &num_config);
+ rarch_assert(result != EGL_FALSE);
+
+ // create an EGL rendering context
+ rpi->mContext = eglCreateContext(rpi->mDisplay, config, EGL_NO_CONTEXT, NULL);
+ rarch_assert(rpi->mContext != EGL_NO_CONTEXT);
+
+ // create an EGL window surface
+ success = graphics_get_display_size(0 /* LCD */, &rpi->mScreenWidth, &rpi->mScreenHeight);
+ rarch_assert(success >= 0);
+
+ dst_rect.x = 0;
+ dst_rect.y = 0;
+ dst_rect.width = rpi->mScreenWidth;
+ dst_rect.height = rpi->mScreenHeight;
+
+ src_rect.x = 0;
+ src_rect.y = 0;
+ src_rect.width = rpi->mScreenWidth << 16;
+ src_rect.height = rpi->mScreenHeight << 16;
+
+ dispman_display = vc_dispmanx_display_open(0 /* LCD */);
+ vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo);
+ dispman_update = vc_dispmanx_update_start(0);
+
+ dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
+ 0/*layer*/, &dst_rect, 0/*src*/,
+ &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, DISPMANX_NO_ROTATE);
+
+ nativewindow.element = dispman_element;
+ nativewindow.width = rpi->mScreenWidth;
+ nativewindow.height = rpi->mScreenHeight;
+ vc_dispmanx_update_submit_sync(dispman_update);
+
+ rpi->mSurface = eglCreateWindowSurface(rpi->mDisplay, config, &nativewindow, NULL);
+ rarch_assert(rpi->mSurface != EGL_NO_SURFACE);
+
+ // connect the context to the surface
+ result = eglMakeCurrent(rpi->mDisplay, rpi->mSurface, rpi->mSurface, rpi->mContext);
+ rarch_assert(result != EGL_FALSE);
+
+ rpi->mTexType = video->rgb32 ? VG_sABGR_8888 : VG_sARGB_1555;
+ rpi->mKeepAspect = video->force_aspect;
+
+ // check for SD televisions: they should always be 4:3
+ if (dispman_modeinfo.width == 720 && (dispman_modeinfo.height == 480 || dispman_modeinfo.height == 576))
+ rpi->mScreenAspect = 4.0f / 3.0f;
+ else
+ rpi->mScreenAspect = (float) dispman_modeinfo.width / dispman_modeinfo.height;
+
+ VGfloat clearColor[4] = {0, 0, 0, 1};
+ vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+
+ rpi->mTextureWidth = rpi->mTextureHeight = video->input_scale * RARCH_SCALE_BASE;
+ // We can't use the native format because there's no sXRGB_1555 type and
+ // emulation cores can send 0 in the top bit. We lose some speed on
+ // conversion but I doubt it has any real affect, since we are only drawing
+ // one image at the end of the day. Still keep the alpha channel for ABGR.
+ rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED);
+ rpi_set_nonblock_state(rpi, !video->vsync);
+
+ linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init();
+ if (linuxraw_input)
+ {
+ *input = (const input_driver_t *)&input_linuxraw;
+ *input_data = linuxraw_input;
+ }
+
+#ifdef HAVE_FREETYPE
+ if (g_settings.video.font_enable)
+ {
+ rpi->mFont = vgCreateFont(0);
+ rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f);
+
+ const char *path = g_settings.video.font_path;
+ if (!*path || !path_file_exists(path))
+ path = font_renderer_get_default_font();
+
+ rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight);
+
+ if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer)
+ {
+ rpi->mFontsOn = true;
+
+ rpi->mPaintFg = vgCreatePaint();
+ rpi->mPaintBg = vgCreatePaint();
+ VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f };
+ VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f };
+
+ vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg);
+
+ vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg);
+ }
+ }
+#endif
+
+ struct sigaction sa;
+ sa.sa_handler = rpi_kill;
+ sa.sa_flags = SA_RESTART;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ return rpi;
+}
+
+static void rpi_free(void *data)
+{
+ rpi_t *rpi = (rpi_t*)data;
+
+ vgDestroyImage(rpi->mImage);
+
+#ifdef HAVE_FREETYPE
+ if (rpi->mFontsOn)
+ {
+ vgDestroyFont(rpi->mFont);
+ font_renderer_free(rpi->mFontRenderer);
+ vgDestroyPaint(rpi->mPaintFg);
+ vgDestroyPaint(rpi->mPaintBg);
+ }
+#endif
+
+ // Release EGL resources
+ eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(rpi->mDisplay, rpi->mSurface);
+ eglDestroyContext(rpi->mDisplay, rpi->mContext);
+ eglTerminate(rpi->mDisplay);
+
+ free(rpi);
+}
+
+#ifdef HAVE_FREETYPE
+
+static void rpi_render_message(rpi_t *rpi, const char *msg)
+{
+ free(rpi->mLastMsg);
+ rpi->mLastMsg = strdup(msg);
+
+ if(rpi->mMsgLength)
+ {
+ while (--rpi->mMsgLength)
+ vgClearGlyph(rpi->mFont, rpi->mMsgLength);
+
+ vgClearGlyph(rpi->mFont, 0);
+ }
+
+ struct font_output_list out;
+ font_renderer_msg(rpi->mFontRenderer, msg, &out);
+ struct font_output *head = out.head;
+
+ while (head)
+ {
+ if (rpi->mMsgLength >= 1024)
+ break;
+
+ VGfloat origin[2], escapement[2];
+ VGImage img;
+
+ escapement[0] = (VGfloat) (head->advance_x);
+ escapement[1] = (VGfloat) (head->advance_y);
+ origin[0] = (VGfloat) (-head->char_off_x);
+ origin[1] = (VGfloat) (head->char_off_y);
+
+ img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED);
+
+ // flip it
+ for (unsigned i = 0; i < head->height; i++)
+ vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1);
+
+ vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement);
+ vgDestroyImage(img);
+
+ rpi->mMsgLength++;
+ head = head->next;
+ }
+
+ font_renderer_free_output(&out);
+
+ for (unsigned i = 0; i < rpi->mMsgLength; i++)
+ rpi->mGlyphIndices[i] = i;
+}
+
+static void rpi_draw_message(rpi_t *rpi, const char *msg)
+{
+ if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg))
+ rpi_render_message(rpi, msg);
+
+ vgSeti(VG_SCISSORING, VG_FALSE);
+ vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
+
+ VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f };
+ vgSetfv(VG_GLYPH_ORIGIN, 2, origins);
+ vgSetPaint(rpi->mPaintBg, VG_FILL_PATH);
+ vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE);
+ origins[0] += 2.0f;
+ origins[1] += 2.0f;
+ vgSetfv(VG_GLYPH_ORIGIN, 2, origins);
+ vgSetPaint(rpi->mPaintFg, VG_FILL_PATH);
+ vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE);
+
+ vgSeti(VG_SCISSORING, VG_TRUE);
+ vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
+}
+
+#endif
+
+static void rpi_calculate_quad(rpi_t *rpi)
+{
+ // set viewport for aspect ratio, taken from the OpenGL driver
+ if (rpi->mKeepAspect)
+ {
+ float desired_aspect = g_settings.video.aspect_ratio;
+
+ // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
+ // assume they are actually equal.
+ if (fabs(rpi->mScreenAspect - desired_aspect) < 0.0001)
+ {
+ rpi->x1 = 0;
+ rpi->y1 = 0;
+ rpi->x2 = rpi->mScreenWidth;
+ rpi->y2 = rpi->mScreenHeight;
+ }
+ else if (rpi->mScreenAspect > desired_aspect)
+ {
+ float delta = (desired_aspect / rpi->mScreenAspect - 1.0) / 2.0 + 0.5;
+ rpi->x1 = rpi->mScreenWidth * (0.5 - delta);
+ rpi->y1 = 0;
+ rpi->x2 = 2.0 * rpi->mScreenWidth * delta + rpi->x1;
+ rpi->y2 = rpi->mScreenHeight + rpi->y1;
+ }
+ else
+ {
+ float delta = (rpi->mScreenAspect / desired_aspect - 1.0) / 2.0 + 0.5;
+ rpi->x1 = 0;
+ rpi->y1 = rpi->mScreenHeight * (0.5 - delta);
+ rpi->x2 = rpi->mScreenWidth + rpi->x1;
+ rpi->y2 = 2.0 * rpi->mScreenHeight * delta + rpi->y1;
+ }
+ }
+ else
+ {
+ rpi->x1 = 0;
+ rpi->y1 = 0;
+ rpi->x2 = rpi->mScreenWidth;
+ rpi->y2 = rpi->mScreenHeight;
+ }
+
+ rpi->scissor[0] = rpi->x1;
+ rpi->scissor[1] = rpi->y1;
+ rpi->scissor[2] = rpi->x2 - rpi->x1;
+ rpi->scissor[3] = rpi->y2 - rpi->y1;
+
+ vgSetiv(VG_SCISSOR_RECTS, 4, rpi->scissor);
+}
+
+static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
+{
+ rpi_t *rpi = (rpi_t*)data;
+
+ if (width != rpi->mRenderWidth || height != rpi->mRenderHeight)
+ {
+ rpi->mRenderWidth = width;
+ rpi->mRenderHeight = height;
+ rpi_calculate_quad(rpi);
+ vguComputeWarpQuadToQuad(
+ rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2,
+ // needs to be flipped, Khronos loves their bottom-left origin
+ 0, height, width, height, width, 0, 0, 0,
+ rpi->mTransformMatrix);
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(rpi->mTransformMatrix);
+ }
+ vgSeti(VG_SCISSORING, VG_FALSE);
+ vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight);
+ vgSeti(VG_SCISSORING, VG_TRUE);
+
+ vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height);
+ vgDrawImage(rpi->mImage);
+
+#ifdef HAVE_FREETYPE
+ if (msg && rpi->mFontsOn)
+ rpi_draw_message(rpi, msg);
+#else
+ (void)msg;
+#endif
+
+ eglSwapBuffers(rpi->mDisplay, rpi->mSurface);
+
+ return true;
+}
+
+static bool rpi_alive(void *data)
+{
+ (void)data;
+ return !rpi_shutdown;
+}
+
+static bool rpi_focus(void *data)
+{
+ (void)data;
+ return true;
+}
+
+const video_driver_t video_rpi = {
+ rpi_init,
+ rpi_frame,
+ rpi_set_nonblock_state,
+ rpi_alive,
+ rpi_focus,
+ NULL,
+ rpi_free,
+ "rpi"
+};
diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c
index 97fec4e17e..a0069c3eba 100644
--- a/input/linuxraw_input.c
+++ b/input/linuxraw_input.c
@@ -1,306 +1,306 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
- * Copyright (C) 2012 - Michael Lelli
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include "../driver.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include "../general.h"
-#include "linuxraw_input.h"
-#include "rarch_sdl_input.h"
-
-static long oldKbmd = 0xFFFF;
-static struct termios oldTerm, newTerm;
-
-struct key_bind
-{
- uint8_t x;
- enum rarch_key sk;
-};
-
-static unsigned keysym_lut[SK_LAST];
-static const struct key_bind lut_binds[] = {
- { KEY_ESC, SK_ESCAPE },
- { KEY_1, SK_1 },
- { KEY_2, SK_2 },
- { KEY_3, SK_3},
- { KEY_4, SK_4 },
- { KEY_5, SK_5 },
- { KEY_6, SK_6 },
- { KEY_7, SK_7 },
- { KEY_8, SK_8 },
- { KEY_9, SK_9 },
- { KEY_0, SK_0 },
- { KEY_MINUS, SK_MINUS },
- { KEY_EQUAL, SK_EQUALS },
- { KEY_BACKSPACE, SK_BACKSPACE },
- { KEY_TAB, SK_TAB },
- { KEY_Q, SK_q },
- { KEY_W, SK_w },
- { KEY_E, SK_e },
- { KEY_R, SK_r },
- { KEY_T, SK_t },
- { KEY_Y, SK_y },
- { KEY_U, SK_u },
- { KEY_I, SK_i },
- { KEY_O, SK_o },
- { KEY_P, SK_p },
- { KEY_LEFTBRACE, SK_LEFTBRACKET },
- { KEY_RIGHTBRACE, SK_RIGHTBRACKET },
- { KEY_ENTER, SK_RETURN },
- { KEY_LEFTCTRL, SK_LCTRL },
- { KEY_A, SK_a },
- { KEY_S, SK_s },
- { KEY_D, SK_d },
- { KEY_F, SK_f },
- { KEY_G, SK_g },
- { KEY_H, SK_h },
- { KEY_J, SK_j },
- { KEY_K, SK_k },
- { KEY_L, SK_l },
- { KEY_SEMICOLON, SK_SEMICOLON },
- { KEY_APOSTROPHE, SK_QUOTE },
- { KEY_GRAVE, SK_BACKQUOTE },
- { KEY_LEFTSHIFT, SK_LSHIFT },
- { KEY_BACKSLASH, SK_BACKSLASH },
- { KEY_Z, SK_z },
- { KEY_X, SK_x },
- { KEY_C, SK_c },
- { KEY_V, SK_v },
- { KEY_B, SK_b },
- { KEY_N, SK_n },
- { KEY_M, SK_m },
- { KEY_COMMA, SK_COMMA },
- { KEY_DOT, SK_PERIOD },
- { KEY_SLASH, SK_SLASH },
- { KEY_RIGHTSHIFT, SK_RSHIFT },
- { KEY_KPASTERISK, SK_KP_MULTIPLY },
- { KEY_LEFTALT, SK_LALT },
- { KEY_SPACE, SK_SPACE },
- { KEY_CAPSLOCK, SK_CAPSLOCK },
- { KEY_F1, SK_F1 },
- { KEY_F2, SK_F2 },
- { KEY_F3, SK_F3 },
- { KEY_F4, SK_F4 },
- { KEY_F5, SK_F5 },
- { KEY_F6, SK_F6 },
- { KEY_F7, SK_F7 },
- { KEY_F8, SK_F8 },
- { KEY_F9, SK_F9 },
- { KEY_F10, SK_F10 },
- { KEY_NUMLOCK, SK_NUMLOCK },
- { KEY_SCROLLLOCK, SK_SCROLLOCK },
- { KEY_KP7, SK_KP7 },
- { KEY_KP8, SK_KP8 },
- { KEY_KP9, SK_KP9 },
- { KEY_KPMINUS, SK_KP_MINUS },
- { KEY_KP4, SK_KP4 },
- { KEY_KP5, SK_KP5 },
- { KEY_KP6, SK_KP6 },
- { KEY_KPPLUS, SK_KP_PLUS },
- { KEY_KP1, SK_KP1 },
- { KEY_KP2, SK_KP2 },
- { KEY_KP3, SK_KP3 },
- { KEY_KP0, SK_KP0 },
- { KEY_KPDOT, SK_KP_PERIOD },
-
- { KEY_F11, SK_F11 },
- { KEY_F12, SK_F12 },
-
- { KEY_KPENTER, SK_KP_ENTER },
- { KEY_RIGHTCTRL, SK_RCTRL },
- { KEY_KPSLASH, SK_KP_DIVIDE },
- { KEY_SYSRQ, SK_PRINT },
- { KEY_RIGHTALT, SK_RALT },
-
- { KEY_HOME, SK_HOME },
- { KEY_UP, SK_UP },
- { KEY_PAGEUP, SK_PAGEUP },
- { KEY_LEFT, SK_LEFT },
- { KEY_RIGHT, SK_RIGHT },
- { KEY_END, SK_END },
- { KEY_DOWN, SK_DOWN },
- { KEY_PAGEDOWN, SK_PAGEDOWN },
- { KEY_INSERT, SK_INSERT },
- { KEY_DELETE, SK_DELETE },
-
- { KEY_PAUSE, SK_PAUSE },
-};
-
-static void init_lut(void)
-{
- memset(keysym_lut, 0, sizeof(keysym_lut));
- for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++)
- keysym_lut[lut_binds[i].sk] = lut_binds[i].x;
-}
-
-static void linuxraw_resetKbmd()
-{
- if (oldKbmd != 0xFFFF)
- {
- ioctl(0, KDSKBMODE, oldKbmd);
- tcsetattr(0, TCSAFLUSH, &oldTerm);
- oldKbmd = 0xFFFF;
- }
-}
-
-static void linuxraw_exitGracefully(int sig)
-{
- linuxraw_resetKbmd();
- kill(getpid(), sig);
-}
-
-static void *linuxraw_input_init(void)
-{
- // only work on terminals
- if (!isatty(0))
- return NULL;
-
- linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw));
- if (!linuxraw)
- return NULL;
-
- if (oldKbmd == 0xFFFF)
- {
- tcgetattr(0, &oldTerm);
- newTerm = oldTerm;
- newTerm.c_lflag &= ~(ECHO | ICANON | ISIG);
- newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
- newTerm.c_cc[VMIN] = 0;
- newTerm.c_cc[VTIME] = 0;
-
- if (ioctl(0, KDGKBMODE, &oldKbmd) != 0)
- return NULL;
- }
-
- tcsetattr(0, TCSAFLUSH, &newTerm);
-
- if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0)
- {
- linuxraw_resetKbmd();
- return NULL;
- }
-
- struct sigaction sa;
- sa.sa_handler = linuxraw_exitGracefully;
- sa.sa_flags = SA_RESTART | SA_RESETHAND;
- sigemptyset(&sa.sa_mask);
- // trap some standard termination codes so we can restore the keyboard before we lose control
- sigaction(SIGABRT, &sa, NULL);
- sigaction(SIGBUS, &sa, NULL);
- sigaction(SIGFPE, &sa, NULL);
- sigaction(SIGILL, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGSEGV, &sa, NULL);
-
- atexit(linuxraw_resetKbmd);
-
- linuxraw->sdl = (sdl_input_t*)input_sdl.init();
- if (!linuxraw->sdl)
- {
- linuxraw_resetKbmd();
- free(linuxraw);
- return NULL;
- }
-
- init_lut();
-
- linuxraw->sdl->use_keyboard = false;
- return linuxraw;
-}
-
-static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key)
-{
- return linuxraw->state[keysym_lut[key]];
-}
-
-static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id)
-{
- if (id < RARCH_BIND_LIST_END)
- {
- const struct snes_keybind *bind = &binds[id];
- return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key);
- }
- else
- return false;
-}
-
-static bool linuxraw_bind_button_pressed(void *data, int key)
-{
- linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
- return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) ||
- input_sdl.key_pressed(linuxraw->sdl, key);
-}
-
-static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
-{
- linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
-
- switch (device)
- {
- case RETRO_DEVICE_JOYPAD:
- return linuxraw_is_pressed(linuxraw, binds[port], id) ||
- input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id);
-
- default:
- return 0;
- }
-}
-
-static void linuxraw_input_free(void *data)
-{
- linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
- input_sdl.free(linuxraw->sdl);
- linuxraw_resetKbmd();
- free(data);
-}
-
-static void linuxraw_input_poll(void *data)
-{
- linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
- uint8_t c;
- uint16_t t;
-
- while (read(0, &c, 1) > 0)
- {
- bool pressed = !(c & 0x80);
- c &= ~0x80;
-
- // ignore extended scancodes
- if (!c)
- read(0, &t, 2);
- else
- linuxraw->state[c] = pressed;
- }
-
- if (linuxraw->state[KEY_C] && (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL]))
- kill(getpid(), SIGINT);
-
- input_sdl.poll(linuxraw->sdl);
-}
-
-const input_driver_t input_linuxraw = {
- linuxraw_input_init,
- linuxraw_input_poll,
- linuxraw_input_state,
- linuxraw_bind_button_pressed,
- linuxraw_input_free,
- "linuxraw"
-};
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
+ * Copyright (C) 2012 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "../driver.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "../general.h"
+#include "linuxraw_input.h"
+#include "rarch_sdl_input.h"
+
+static long oldKbmd = 0xFFFF;
+static struct termios oldTerm, newTerm;
+
+struct key_bind
+{
+ uint8_t x;
+ enum rarch_key sk;
+};
+
+static unsigned keysym_lut[SK_LAST];
+static const struct key_bind lut_binds[] = {
+ { KEY_ESC, SK_ESCAPE },
+ { KEY_1, SK_1 },
+ { KEY_2, SK_2 },
+ { KEY_3, SK_3},
+ { KEY_4, SK_4 },
+ { KEY_5, SK_5 },
+ { KEY_6, SK_6 },
+ { KEY_7, SK_7 },
+ { KEY_8, SK_8 },
+ { KEY_9, SK_9 },
+ { KEY_0, SK_0 },
+ { KEY_MINUS, SK_MINUS },
+ { KEY_EQUAL, SK_EQUALS },
+ { KEY_BACKSPACE, SK_BACKSPACE },
+ { KEY_TAB, SK_TAB },
+ { KEY_Q, SK_q },
+ { KEY_W, SK_w },
+ { KEY_E, SK_e },
+ { KEY_R, SK_r },
+ { KEY_T, SK_t },
+ { KEY_Y, SK_y },
+ { KEY_U, SK_u },
+ { KEY_I, SK_i },
+ { KEY_O, SK_o },
+ { KEY_P, SK_p },
+ { KEY_LEFTBRACE, SK_LEFTBRACKET },
+ { KEY_RIGHTBRACE, SK_RIGHTBRACKET },
+ { KEY_ENTER, SK_RETURN },
+ { KEY_LEFTCTRL, SK_LCTRL },
+ { KEY_A, SK_a },
+ { KEY_S, SK_s },
+ { KEY_D, SK_d },
+ { KEY_F, SK_f },
+ { KEY_G, SK_g },
+ { KEY_H, SK_h },
+ { KEY_J, SK_j },
+ { KEY_K, SK_k },
+ { KEY_L, SK_l },
+ { KEY_SEMICOLON, SK_SEMICOLON },
+ { KEY_APOSTROPHE, SK_QUOTE },
+ { KEY_GRAVE, SK_BACKQUOTE },
+ { KEY_LEFTSHIFT, SK_LSHIFT },
+ { KEY_BACKSLASH, SK_BACKSLASH },
+ { KEY_Z, SK_z },
+ { KEY_X, SK_x },
+ { KEY_C, SK_c },
+ { KEY_V, SK_v },
+ { KEY_B, SK_b },
+ { KEY_N, SK_n },
+ { KEY_M, SK_m },
+ { KEY_COMMA, SK_COMMA },
+ { KEY_DOT, SK_PERIOD },
+ { KEY_SLASH, SK_SLASH },
+ { KEY_RIGHTSHIFT, SK_RSHIFT },
+ { KEY_KPASTERISK, SK_KP_MULTIPLY },
+ { KEY_LEFTALT, SK_LALT },
+ { KEY_SPACE, SK_SPACE },
+ { KEY_CAPSLOCK, SK_CAPSLOCK },
+ { KEY_F1, SK_F1 },
+ { KEY_F2, SK_F2 },
+ { KEY_F3, SK_F3 },
+ { KEY_F4, SK_F4 },
+ { KEY_F5, SK_F5 },
+ { KEY_F6, SK_F6 },
+ { KEY_F7, SK_F7 },
+ { KEY_F8, SK_F8 },
+ { KEY_F9, SK_F9 },
+ { KEY_F10, SK_F10 },
+ { KEY_NUMLOCK, SK_NUMLOCK },
+ { KEY_SCROLLLOCK, SK_SCROLLOCK },
+ { KEY_KP7, SK_KP7 },
+ { KEY_KP8, SK_KP8 },
+ { KEY_KP9, SK_KP9 },
+ { KEY_KPMINUS, SK_KP_MINUS },
+ { KEY_KP4, SK_KP4 },
+ { KEY_KP5, SK_KP5 },
+ { KEY_KP6, SK_KP6 },
+ { KEY_KPPLUS, SK_KP_PLUS },
+ { KEY_KP1, SK_KP1 },
+ { KEY_KP2, SK_KP2 },
+ { KEY_KP3, SK_KP3 },
+ { KEY_KP0, SK_KP0 },
+ { KEY_KPDOT, SK_KP_PERIOD },
+
+ { KEY_F11, SK_F11 },
+ { KEY_F12, SK_F12 },
+
+ { KEY_KPENTER, SK_KP_ENTER },
+ { KEY_RIGHTCTRL, SK_RCTRL },
+ { KEY_KPSLASH, SK_KP_DIVIDE },
+ { KEY_SYSRQ, SK_PRINT },
+ { KEY_RIGHTALT, SK_RALT },
+
+ { KEY_HOME, SK_HOME },
+ { KEY_UP, SK_UP },
+ { KEY_PAGEUP, SK_PAGEUP },
+ { KEY_LEFT, SK_LEFT },
+ { KEY_RIGHT, SK_RIGHT },
+ { KEY_END, SK_END },
+ { KEY_DOWN, SK_DOWN },
+ { KEY_PAGEDOWN, SK_PAGEDOWN },
+ { KEY_INSERT, SK_INSERT },
+ { KEY_DELETE, SK_DELETE },
+
+ { KEY_PAUSE, SK_PAUSE },
+};
+
+static void init_lut(void)
+{
+ memset(keysym_lut, 0, sizeof(keysym_lut));
+ for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++)
+ keysym_lut[lut_binds[i].sk] = lut_binds[i].x;
+}
+
+static void linuxraw_resetKbmd()
+{
+ if (oldKbmd != 0xFFFF)
+ {
+ ioctl(0, KDSKBMODE, oldKbmd);
+ tcsetattr(0, TCSAFLUSH, &oldTerm);
+ oldKbmd = 0xFFFF;
+ }
+}
+
+static void linuxraw_exitGracefully(int sig)
+{
+ linuxraw_resetKbmd();
+ kill(getpid(), sig);
+}
+
+static void *linuxraw_input_init(void)
+{
+ // only work on terminals
+ if (!isatty(0))
+ return NULL;
+
+ linuxraw_input_t *linuxraw = (linuxraw_input_t*)calloc(1, sizeof(*linuxraw));
+ if (!linuxraw)
+ return NULL;
+
+ if (oldKbmd == 0xFFFF)
+ {
+ tcgetattr(0, &oldTerm);
+ newTerm = oldTerm;
+ newTerm.c_lflag &= ~(ECHO | ICANON | ISIG);
+ newTerm.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
+ newTerm.c_cc[VMIN] = 0;
+ newTerm.c_cc[VTIME] = 0;
+
+ if (ioctl(0, KDGKBMODE, &oldKbmd) != 0)
+ return NULL;
+ }
+
+ tcsetattr(0, TCSAFLUSH, &newTerm);
+
+ if (ioctl(0, KDSKBMODE, K_MEDIUMRAW) != 0)
+ {
+ linuxraw_resetKbmd();
+ return NULL;
+ }
+
+ struct sigaction sa;
+ sa.sa_handler = linuxraw_exitGracefully;
+ sa.sa_flags = SA_RESTART | SA_RESETHAND;
+ sigemptyset(&sa.sa_mask);
+ // trap some standard termination codes so we can restore the keyboard before we lose control
+ sigaction(SIGABRT, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+ sigaction(SIGFPE, &sa, NULL);
+ sigaction(SIGILL, &sa, NULL);
+ sigaction(SIGQUIT, &sa, NULL);
+ sigaction(SIGSEGV, &sa, NULL);
+
+ atexit(linuxraw_resetKbmd);
+
+ linuxraw->sdl = (sdl_input_t*)input_sdl.init();
+ if (!linuxraw->sdl)
+ {
+ linuxraw_resetKbmd();
+ free(linuxraw);
+ return NULL;
+ }
+
+ init_lut();
+
+ linuxraw->sdl->use_keyboard = false;
+ return linuxraw;
+}
+
+static bool linuxraw_key_pressed(linuxraw_input_t *linuxraw, int key)
+{
+ return linuxraw->state[keysym_lut[key]];
+}
+
+static bool linuxraw_is_pressed(linuxraw_input_t *linuxraw, const struct snes_keybind *binds, unsigned id)
+{
+ if (id < RARCH_BIND_LIST_END)
+ {
+ const struct snes_keybind *bind = &binds[id];
+ return bind->valid && linuxraw_key_pressed(linuxraw, binds[id].key);
+ }
+ else
+ return false;
+}
+
+static bool linuxraw_bind_button_pressed(void *data, int key)
+{
+ linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
+ return linuxraw_is_pressed(linuxraw, g_settings.input.binds[0], key) ||
+ input_sdl.key_pressed(linuxraw->sdl, key);
+}
+
+static int16_t linuxraw_input_state(void *data, const struct snes_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
+{
+ linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
+
+ switch (device)
+ {
+ case RETRO_DEVICE_JOYPAD:
+ return linuxraw_is_pressed(linuxraw, binds[port], id) ||
+ input_sdl.input_state(linuxraw->sdl, binds, port, device, index, id);
+
+ default:
+ return 0;
+ }
+}
+
+static void linuxraw_input_free(void *data)
+{
+ linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
+ input_sdl.free(linuxraw->sdl);
+ linuxraw_resetKbmd();
+ free(data);
+}
+
+static void linuxraw_input_poll(void *data)
+{
+ linuxraw_input_t *linuxraw = (linuxraw_input_t*)data;
+ uint8_t c;
+ uint16_t t;
+
+ while (read(0, &c, 1) > 0)
+ {
+ bool pressed = !(c & 0x80);
+ c &= ~0x80;
+
+ // ignore extended scancodes
+ if (!c)
+ read(0, &t, 2);
+ else
+ linuxraw->state[c] = pressed;
+ }
+
+ if (linuxraw->state[KEY_C] && (linuxraw->state[KEY_LEFTCTRL] || linuxraw->state[KEY_RIGHTCTRL]))
+ kill(getpid(), SIGINT);
+
+ input_sdl.poll(linuxraw->sdl);
+}
+
+const input_driver_t input_linuxraw = {
+ linuxraw_input_init,
+ linuxraw_input_poll,
+ linuxraw_input_state,
+ linuxraw_bind_button_pressed,
+ linuxraw_input_free,
+ "linuxraw"
+};