From 1855a7ea0d420ee0d38c2bf003f9c26fa86ba7cc Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 11 May 2011 18:40:03 +0200 Subject: [PATCH] Add driver stuff. --- gfx/ext.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 gfx/ext.c diff --git a/gfx/ext.c b/gfx/ext.c new file mode 100644 index 0000000000..cc819e3990 --- /dev/null +++ b/gfx/ext.c @@ -0,0 +1,288 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2011 - Hans-Kristian Arntzen + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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. + * + * SSNES 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 SSNES. + * If not, see . + */ + +// Loader for external API plugins. + +#include "ext/ssnes_video.h" +#include +#include +#include "dynamic.h" +#include "general.h" + +/////////// Input hook + +typedef struct +{ + const ssnes_input_driver_t *driver; + void *handle; +} input_ext_t; + +static void* input_ext_init(void) +{ + return calloc(1, sizeof(input_ext_t)); +} + +static void input_ext_poll(void *data) +{ + input_ext_t *ext = data; + ext->driver->poll(ext->handle); +} + +static int16_t input_ext_input_state(void *data, const struct snes_keybind **snes_keybinds, bool port, unsigned device, unsigned index, unsigned id) +{ + input_ext_t *ext = data; + + unsigned player = 0; + if (device == SNES_DEVICE_MULTITAP) + player = (port == SNES_PORT_1) ? 1 : index + 2; + else + player = (port == SNES_PORT_1) ? 1 : 2; + + const struct snes_keybind *ssnes_bind = NULL; + + for (unsigned i = 0; g_settings.input.binds[player - 1][i].id != -1; i++) + { + if (g_settings.input.binds[player - 1][i].id == id) + { + ssnes_bind = &g_settings.input.binds[player - 1][i]; + break; + } + } + + if (ssnes_bind) + { + struct ssnes_keybind bind = { + .key = ssnes_bind->key, + .joykey = ssnes_bind->joykey, + .joyaxis = ssnes_bind->joyaxis + }; + + return ext->driver->input_state(ext->handle, &bind, player); + } + else + return 0; +} + +static bool input_ext_key_pressed(void *data, int key) +{ + input_ext_t *ext = data; + + const struct snes_keybind *ssnes_bind = NULL; + for (unsigned i = 0; g_settings.input.binds[0][i].id != -1; i++) + { + if (g_settings.input.binds[0][i].id == key) + { + ssnes_bind = &g_settings.input.binds[0][i]; + break; + } + } + + if (ssnes_bind) + { + struct ssnes_keybind bind = { + .key = ssnes_bind->key, + .joykey = ssnes_bind->joykey, + .joyaxis = ssnes_bind->joyaxis + }; + + return ext->driver->input_state(ext->handle, &bind, 1); + } + else + return false; +} + +static void input_ext_free(void *data) +{ + input_ext_t *ext = data; + if (ext) + { + ext->driver->free(ext->handle); + free(ext); + } +} + +static const input_driver_t input_ext = { + .init = input_ext_init, + .poll = input_ext_poll, + .input_state = input_ext_input_state, + .key_pressed = input_ext_key_pressed, + .free = input_ext_free, + .ident = "ext" +}; + + +//////////// Video hook +typedef struct +{ + dylib_t lib; + const ssnes_video_driver_t *driver; + void *handle; +} ext_t; + +static void video_ext_free(void *data) +{ + ext_t *ext = data; + if (ext) + { + ext->driver->free(ext->handle); + dylib_close(ext->lib); + free(ext); + } +} + +static bool video_ext_focus(void *data) +{ + ext_t *ext = data; + return ext->driver->focus(ext->handle); +} + +static bool video_ext_alive(void *data) +{ + ext_t *ext = data; + return ext->driver->alive(ext->handle); +} + +static void video_ext_set_nonblock_state(void *data, bool state) +{ + ext_t *ext = data; + ext->driver->set_nonblock_state(ext->handle, state); +} + +static bool video_ext_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) +{ + ext_t *ext = data; + return ext->driver->frame(ext->handle, frame, width, height, pitch, msg); +} + +static void* setup_input(ext_t *ext, const ssnes_input_driver_t *driver) +{ + int joypad_index[5]; + for (unsigned i = 0; i < 5; i++) + joypad_index[i] = g_settings.input.joypad_map[i] == SSNES_NO_JOYPAD ? -1 : g_settings.input.joypad_map[i]; + + void *handle = driver->init(joypad_index); + if (!handle) + return NULL; + + input_ext_t *wrap_handle = input_ext.init(); + if (!wrap_handle) + return NULL; + + wrap_handle->handle = handle; + wrap_handle->driver = driver; + + return wrap_handle; +} + +static bool setup_video(ext_t *ext, const video_info_t *video, const input_driver_t **input, void **input_data) +{ + SSNES_LOG("Loaded driver: \"%s\"\n", ext->driver->ident ? ext->driver->ident : "Unknown"); + + if (SSNES_API_VERSION != ext->driver->api_version) + { + SSNES_ERR("API version mismatch detected!\n"); + SSNES_ERR("Required API version: %d, Library version: %d\n", SSNES_API_VERSION, ext->driver->api_version); + return false; + } + + ssnes_video_info_t info = { + .width = video->width, + .height = video->height, + .fullscreen = video->fullscreen, + .vsync = video->vsync, + .force_aspect = video->force_aspect, + .aspect_ratio = g_settings.video.aspect_ratio, + .smooth = video->smooth, + .input_scale = video->input_scale, + .color_format = video->rgb32 ? SSNES_COLOR_FORMAT_ARGB8888 : SSNES_COLOR_FORMAT_XRGB1555, + .xml_shader = g_settings.video.bsnes_shader_path, + .cg_shader = g_settings.video.cg_shader_path, + .ttf_font = *g_settings.video.font_path ? g_settings.video.font_path : NULL, + .ttf_font_size = g_settings.video.font_size + }; + + const ssnes_input_driver_t *input_driver = NULL; + void *input_driver_handle = NULL; + ext->handle = ext->driver->init(&info, &input_driver, &input_driver_handle); + if (!ext->handle) + return false; + + *input = input_driver ? &input_ext : NULL; + if (input_driver) + *input_data = setup_input(ext, input_driver); + else + *input_data = NULL; + + return true; +} + +static void* video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data) +{ + ext_t *ext = calloc(1, sizeof(*ext)); + if (!ext) + return NULL; + + if (!(*g_settings.video.external_driver)) + { + SSNES_ERR("External driver needs video_external_driver path to be set!\n"); + goto error; + } + + ext->lib = dylib_load(g_settings.video.external_driver); + if (!ext->lib) + { + SSNES_ERR("Failed to open library: \"%s\"\n", g_settings.video.external_driver); + goto error; + } + + const ssnes_video_driver_t* (*video_init)(void) = dylib_proc(ext->lib, "ssnes_video_init"); + if (!video_init) + { + SSNES_ERR("Couldn't find function ssnes_video_init in library ...\n"); + goto error; + } + + ext->driver = video_init(); + if (!ext->driver) + { + SSNES_ERR("External driver returned invalid driver handle.\n"); + goto error; + } + + if (!setup_video(ext, video, input, input_data)) + { + SSNES_ERR("Failed to start driver.\n"); + goto error; + } + + return ext; + +error: + video_ext_free(ext); + return NULL; +} + +const video_driver_t video_ext = { + .init = video_ext_init, + .frame = video_ext_frame, + .alive = video_ext_alive, + .set_nonblock_state = video_ext_set_nonblock_state, + .focus = video_ext_focus, + .free = video_ext_free, + .ident = "ext" +}; +