Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libretro: Add mouse support #31

Merged
merged 4 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/onsyuri_libretro/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.14)
project(sdlpop-onscripter C CXX)
project(onsyuri-libretro C CXX)
option(LIBRETRO_STATIC "Statically link the libretro core" OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 11)
Expand Down
74 changes: 55 additions & 19 deletions src/onsyuri_libretro/SDL_libretro.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
#include "SDL_libretro.h"
#include "SDL_image.h"
#include "./deps/SDL/src/audio/SDL_sysaudio.h"
#include "./deps/SDL/src/events/SDL_keyboard_c.h"
#include "./deps/SDL/src/events/SDL_mouse_c.h"
#include "./deps/SDL/src/video/SDL_sysvideo.h"
#include "cursor_png.h"

static SDL_Surface* _surface = NULL;
static SDL_Surface* _surface_real = NULL;
static SDL_Surface* _cursor = NULL;
static SDL_Surface* _surface_fb = NULL; // backbuffer
static SDL_Surface* _surface_ons = NULL; // updated screen
static SDL_Surface* _surface_retro = NULL; // screen with mouse cursor
static SDL_AudioDevice* _audio = NULL;
static SDL_VideoDevice* _video = NULL;

static int
VideoInit(SDL_VideoDevice* device)
Expand All @@ -18,6 +24,12 @@ VideoInit(SDL_VideoDevice* device)
mode.refresh_rate = 60;
mode.driverdata = NULL;
SDL_AddBasicVideoDisplay(&mode);

_cursor = IMG_Load_RW(SDL_RWFromConstMem(cursor_png, cursor_png_len), 1);
if (_cursor == NULL) {
return -1;
}
_video = device;
return 0;
}

Expand All @@ -30,6 +42,7 @@ static void
VideoFree(SDL_VideoDevice* device)
{
SDL_free(device);
SDL_FreeSurface(_cursor);
}

static void
Expand All @@ -40,8 +53,9 @@ PumpEvents(SDL_VideoDevice* device)
void
DestroyWindowFramebuffer(SDL_VideoDevice* device, SDL_Window* window)
{
SDL_FreeSurface(_surface);
SDL_FreeSurface(_surface_real);
SDL_FreeSurface(_surface_fb);
SDL_FreeSurface(_surface_ons);
SDL_FreeSurface(_surface_retro);
}

int
Expand All @@ -59,16 +73,17 @@ CreateWindowFramebuffer(SDL_VideoDevice* device,

/* Create a new one */
SDL_GetWindowSizeInPixels(window, &w, &h);
_surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format);
_surface_real = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format);
if (!_surface_real) {
_surface_fb = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format);
_surface_ons = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format);
_surface_retro = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format);
if (_surface_fb == NULL || _surface_ons == NULL || _surface_retro == NULL) {
return -1;
}

/* Save the info and return! */
*format = surface_format;
*pixels = _surface->pixels;
*pitch = _surface->pitch;
*pixels = _surface_fb->pixels;
*pitch = _surface_fb->pitch;

return 0;
}
Expand All @@ -80,8 +95,7 @@ UpdateWindowFramebuffer(SDL_VideoDevice* device,
int numrects)
{
for (int i = 0; i < numrects; i += 1) {
SDL_BlitSurface(
_surface, (SDL_Rect*)&rects[i], _surface_real, (SDL_Rect*)&rects[i]);
SDL_BlitSurface(_surface_fb, (SDL_Rect*)&rects[i], _surface_ons, (SDL_Rect*)&rects[i]);
}
return 0;
}
Expand Down Expand Up @@ -147,25 +161,35 @@ AudioBootStrap DUMMYAUDIO_bootstrap = { "libretro",
void
SDL_libretro_RefreshVideo(retro_video_refresh_t video_cb)
{
if (_surface_real == NULL)
if (_surface_retro == NULL)
return;

video_cb(_surface_real->pixels,
_surface_real->w,
_surface_real->h,
_surface_real->pitch);
SDL_Mouse *mouse = SDL_GetMouse();

if (mouse->cursor_shown) {
SDL_Rect mouse_rect = { mouse->x, mouse->y, _cursor->w, _cursor->h };
SDL_BlitSurface(_surface_ons, NULL, _surface_retro, NULL);
SDL_BlitSurface(_cursor, NULL, _surface_retro, &mouse_rect);

video_cb(_surface_retro->pixels,
_surface_retro->w,
_surface_retro->h,
_surface_retro->pitch);
} else {
video_cb(_surface_ons->pixels,
_surface_ons->w,
_surface_ons->h,
_surface_ons->pitch);
}
}

void
SDL_libretro_ProduceAudio(retro_audio_sample_batch_t audio_batch_cb)
{
if (_audio == NULL)
return;

SDL_LockAudio();
_audio->spec.callback(_audio, _audio->work_buffer, _audio->spec.size);
audio_batch_cb((const int16_t*)_audio->work_buffer, _audio->spec.samples);
SDL_UnlockAudio();
}

void
Expand Down Expand Up @@ -312,3 +336,15 @@ SDL_libretro_KeyboardCallback(bool down,
SDL_Scancode scancode = SDL_GetScancodeFromKey(keycodes[keycode]);
SDL_SendKeyboardKey(down ? SDL_PRESSED : SDL_RELEASED, scancode);
}

void
SDL_libretro_SendMouseMotion(int relative, int x, int y)
{
SDL_SendMouseMotion(_video->grabbed_window, 0, relative, x, y);
}

void
SDL_libretro_SendMouseButton(Uint8 state, Uint8 button)
{
SDL_SendMouseButton(_video->grabbed_window, 0, state, button);
}
2 changes: 2 additions & 0 deletions src/onsyuri_libretro/SDL_libretro.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ void SDL_libretro_RefreshVideo(retro_video_refresh_t video_cb);
void SDL_libretro_ProduceAudio(retro_audio_sample_batch_t audio_batch_t);
void SDL_libretro_KeyboardCallback(bool down, unsigned keycode,
uint32_t character, uint16_t key_modifiers);
void SDL_libretro_SendMouseMotion(int relative, int x, int y);
void SDL_libretro_SendMouseButton(Uint8 state, Uint8 button);

int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode);

Expand Down
7 changes: 7 additions & 0 deletions src/onsyuri_libretro/cursor_png.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Generated by adobe-bin2c from 'left-arrow' in the KDE breeze theme.

const char cursor_png[] = "\
\211PNG\r\n\
\032\n\
\000\000\000\rIHDR\000\000\000(\000\000\000(\b\006\000\000\000\214\376\270m\000\000\002\217IDATX\205\355\327\277O\023a\034\307\361\367\035\327\213\325JPK\032!\232\0207\\D\302\302\330\030\247\".mB\330T\026\313`\354\000[G\231\b\033\211\t\t\306\305\201\211\215 !\370\027\320\260\230\100\241cCZ \222\273 \367\343\353p-\026A\244\320\037\227\330Or\303\rO\236\327}\356y.\367\100+\377S\322\351\264j\333v\322\262\254\227\200\322l\317\237Q\212\305\342\240\210\210eY\356\321\321\321;\100m6\252\022\240\356\357\357w\210\b\243\243\243\212\252\252\323\246i\372\002Y\216\266\261\2611\344\272\256\000\222H\044\344\370\370\330=<<L\341\023\244\226\311d^\224\201\370\020y\006\210\317\220\347\002\375\204\374+\320/\310\v\201~\100\376\023\bH<\036o\032\362R\300f\"/\rl\026\262*`3\220U\003\033\215\274\022\260\022i\232\346\373z\"\265\365\365\365\241\253\000\001\031\031\031\021\313\262\334\275\275\275\0305\374U\323\2563XUU\372\372\372\210\305b\044\022\t4MSL\323\274\207\327\242S\033\342\357T\325`4\032\225|>/\2458\205B\341\333\362\362\362+\340\016\327|\360S\250\253\016\f\006\203D\"\021wkk\353\323\334\334\334\227\251\251\251,`\000\077\001\267V\300\312\234\273I:;;\245\247\247\347L\203\375\375\375\"\"2<<\374\004\210\000\355\300\r\240\255\036\2703\300P(\044\023\023\023rpp \333\333\333\022\016\207O\001\273\273\273EDduu\365Y\005\254\256\347\230\2235\230J\245\244P(\210\210\210a\0309\3030\262+++\022\b\004N\200\272\256\213\210H.\227{C\r\327\334\205\300\371\371\371\307\266m\033\216\343\330\273\273\273_\027\026\026^\353\272\336;99\371\334\262\254\037\263\263\263'\300\201\201\001\021\021\311\347\363i \320\b`\033\320\236L&\237\216\215\215\r\002\217\200. \f\334_[[\033\027\021wqqQfff\244X,\212\210\310\346\346\3468\240\323\200c\252R\232\250\003\270\v\334\306[[\001\340&\320\225\315f\077JE\f\303\370\036\217\307\037\322\240\006\313H\255t\251\245{\005\257\335\020\360`ii\351\355\316\316\316\347L&\363!\032\215\366\342\355\336\272\355\334j^\213\006\004\201[xM;x\337=\003\260\361\326f\315S\rP\301k\265\334\256\340\301\034\352\204+Oz\2351u\203\265\322J+\255\264\342\345\027\024\370D\205o\345\302~\000\000\000\000IEND\256B`\202";
const size_t cursor_png_len = sizeof(cursor_png) - 1;
123 changes: 114 additions & 9 deletions src/onsyuri_libretro/libretro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>

#include <string>

#include "ONScripter.h"
#include "SDL_libretro.h"
#include "gbk2utf16.h"
Expand All @@ -19,6 +17,8 @@ static retro_input_state_t input_state_cb;
static retro_audio_sample_batch_t audio_batch_cb;

static SDL_Thread* game_thread;
static bool classical_mouse = false;
static double mouse_sensitivity = 1.0;

ONScripter ons;
Coding2UTF16* coding2utf16 = NULL;
Expand Down Expand Up @@ -54,6 +54,23 @@ retro_set_environment(retro_environment_t cb)
.values = { { "GBK" }, { "SHIFTJIS" }, { NULL } },
.default_value = "GBK",
},
{
.key = "onsyuri_mouse_mode",
.desc = "Mouse Mode",
.info = NULL,
.values = { { "Touch" }, { "Classical" }, { NULL } },
.default_value = "Classical",
},
{
.key = "onsyuri_mouse_sensitivity",
.desc = "Classical Mouse Sensitivity",
.info = NULL,
.values = {
{ "0.4" }, { "0.6" }, { "0.8" }, { "1.0" }, { "1.2" }, { "1.4" },
{ "1.6" }, { "1.8" }, { "2.0" }, { "2.2" }, { "2.4" }, { "2.6 "},
},
.default_value = "1.0",
},
NULL,
};

Expand Down Expand Up @@ -102,7 +119,7 @@ retro_get_system_info(struct retro_system_info* info)
{
info->need_fullpath = true;
info->valid_extensions = "txt|dat|___";
info->library_version = "0.1";
info->library_version = "0.7.4+1";
info->library_name = "onsyuri";
info->block_extract = false;
}
Expand All @@ -126,17 +143,27 @@ apply_variables()
{
struct retro_variable var = { 0 };
var.key = "onsyuri_script_encoding";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) {
if (coding2utf16 != NULL) {
delete coding2utf16;
coding2utf16 = NULL;
}
// Need restart to change the coding
if (coding2utf16 == NULL && environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) {
if (strcmp(var.value, "SHIFTJIS") == 0) {
coding2utf16 = new SJIS2UTF16();
} else {
coding2utf16 = new GBK2UTF16();
}
}
var.key = "onsyuri_mouse_mode";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) {
if (strcmp(var.value, "Classical") == 0) {
classical_mouse = true;
} else {
classical_mouse = false;
}
}
SDL_ShowCursor(classical_mouse ? SDL_ENABLE : SDL_DISABLE);
var.key = "onsyuri_mouse_sensitivity";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) {
mouse_sensitivity = SDL_atof(var.value);
}
}

void
Expand All @@ -160,7 +187,6 @@ retro_load_game(const struct retro_game_info* game)
return false;

char* gamedir = dirname(SDL_strdup(game->path));
ons.setArchivePath(gamedir);
chdir(gamedir);

apply_variables();
Expand All @@ -172,6 +198,8 @@ retro_load_game(const struct retro_game_info* game)
return false;
}

SDL_CaptureMouse(SDL_TRUE);

struct retro_keyboard_callback keyboard = {
.callback = SDL_libretro_KeyboardCallback,
};
Expand Down Expand Up @@ -229,11 +257,88 @@ PumpJoypadEvents(void)
}
}

static Uint8
pressed_to_button(int16_t pressed)
{
if (pressed == 1)
return SDL_BUTTON_LEFT;
if (pressed == 2)
return SDL_BUTTON_RIGHT;
return 0;
}

static void
PumpMouseEvents(void)
{
#define MOUSE(X) input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_##X)
#define POINTER(X) input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_##X)
if (classical_mouse) {
static int16_t _left = 0;
static int16_t _right = 0;
int16_t dx = MOUSE(X);
int16_t dy = MOUSE(Y);
int16_t left = MOUSE(LEFT);
int16_t right = MOUSE(RIGHT);

if (dx != 0 || dy != 0) {
SDL_libretro_SendMouseMotion(1, dx * mouse_sensitivity, dy * mouse_sensitivity);
}
if (left != _left) {
SDL_libretro_SendMouseButton(left ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
_left = left;
}
if (right != _right) {
SDL_libretro_SendMouseButton(right ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
_right = right;
}
} else {
static int16_t _x = 0;
static int16_t _y = 0;
static int16_t _pressed = 0;

int width = ons.getWidth();
int height = ons.getHeight();
int16_t x = POINTER(X);
int16_t y = POINTER(Y);
int16_t pressed = 0;
while (input_state_cb(0, RETRO_DEVICE_POINTER, pressed,
RETRO_DEVICE_ID_POINTER_PRESSED))
pressed += 1;
if (MOUSE(LEFT))
pressed = 1;
if (MOUSE(RIGHT))
pressed = 2;

x = width * (x + 0x7fff) / 0xffff;
y = height * (y + 0x7fff) / 0xffff;
if (x != _x || y != _y) {
SDL_libretro_SendMouseMotion(0, x, y);
_x = x;
_y = y;
}
if (pressed != _pressed) {
if (_pressed)
SDL_libretro_SendMouseButton(SDL_RELEASED, pressed_to_button(_pressed));
else
SDL_libretro_SendMouseButton(SDL_PRESSED, pressed_to_button(pressed));
_pressed = pressed;
}
}
#undef MOUSE
#undef POINTER
}

void
retro_run(void)
{
bool vupdated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &vupdated) && vupdated) {
apply_variables();
}

input_poll_cb();
PumpJoypadEvents();
PumpMouseEvents();

SDL_libretro_RefreshVideo(video_cb);
SDL_libretro_ProduceAudio(audio_batch_cb);
Expand Down
Loading