added all 4 controllers by default to avoid extra joystick added / removed state handling

added explicit update polling callback made controller_input callback take in the actual dreamcast button pressed
removed controller profile code from maple
This commit is contained in:
Anthony Pesch 2017-04-30 19:51:23 -04:00
parent e54fc92cfd
commit c0a713613c
13 changed files with 131 additions and 274 deletions

View File

@ -65,16 +65,8 @@ struct emu {
struct list live_frames;
};
/*
* multithreaded, offscreen video rendering
*/
static void emu_cancel_render(struct emu *emu) {
mutex_lock(emu->pending_mutex);
emu->pending_ctx = NULL;
cond_signal(emu->pending_cond);
mutex_unlock(emu->pending_mutex);
static int16_t emu_get_input(void *userdata, int port, int button) {
return 0;
}
static void emu_finish_render(void *userdata) {
@ -118,6 +110,18 @@ static void emu_push_audio(void *userdata, const int16_t *data, int frames) {
ringbuf_advance_write_ptr(emu->audio_buffer, size);
}
/*
* multithreaded, offscreen video rendering
*/
static void emu_cancel_render(struct emu *emu) {
mutex_lock(emu->pending_mutex);
emu->pending_ctx = NULL;
cond_signal(emu->pending_cond);
mutex_unlock(emu->pending_mutex);
}
static struct frame *emu_pop_frame(struct emu *emu) {
mutex_lock(emu->frames_mutex);
@ -274,18 +278,6 @@ static void emu_keydown(void *data, int device_index, enum keycode code,
dc_keydown(emu->dc, device_index, code, value);
}
static void emu_joy_add(void *data, int joystick_index) {
struct emu *emu = data;
dc_joy_add(emu->dc, joystick_index);
}
static void emu_joy_remove(void *data, int joystick_index) {
struct emu *emu = data;
dc_joy_remove(emu->dc, joystick_index);
}
static void emu_close(void *data) {
struct emu *emu = data;
@ -510,8 +502,8 @@ struct emu *emu_create(struct window *win) {
emu->win = win;
/* add window input listeners */
emu->listener = (struct window_listener){
emu, &emu_joy_add, &emu_joy_remove, &emu_keydown, NULL, &emu_close, {0}};
emu->listener =
(struct window_listener){emu, &emu_keydown, NULL, &emu_close, {0}};
win_add_listener(emu->win, &emu->listener);
/* create dreamcast */
@ -520,6 +512,8 @@ struct emu *emu_create(struct window *win) {
client.push_audio = &emu_push_audio;
client.start_render = &emu_start_render;
client.finish_render = &emu_finish_render;
client.poll_input = NULL;
client.get_input = &emu_get_input;
emu->dc = dc_create(&client);
/* create render backend */

View File

@ -17,38 +17,44 @@
DEFINE_OPTION_INT(gdb, 0, "Run gdb debug server");
void dc_finish_render(struct dreamcast *dc) {
if (dc->client.finish_render) {
dc->client.finish_render(dc->client.userdata);
int16_t dc_get_input(struct dreamcast *dc, int port, int button) {
if (!dc->client.get_input) {
return 0;
}
return dc->client.get_input(dc->client.userdata, port, button);
}
void dc_poll_input(struct dreamcast *dc) {
if (!dc->client.poll_input) {
return;
}
dc->client.poll_input(dc->client.userdata);
}
void dc_finish_render(struct dreamcast *dc) {
if (!dc->client.finish_render) {
return;
}
dc->client.finish_render(dc->client.userdata);
}
void dc_start_render(struct dreamcast *dc, struct tile_ctx *ctx) {
if (dc->client.start_render) {
dc->client.start_render(dc->client.userdata, ctx);
if (!dc->client.start_render) {
return;
}
dc->client.start_render(dc->client.userdata, ctx);
}
void dc_push_audio(struct dreamcast *dc, const int16_t *data, int frames) {
if (dc->client.push_audio) {
dc->client.push_audio(dc->client.userdata, data, frames);
if (!dc->client.push_audio) {
return;
}
}
void dc_joy_remove(struct dreamcast *dc, int joystick_index) {
list_for_each_entry(dev, &dc->devices, struct device, it) {
if (dev->window_if && dev->window_if->joy_remove) {
dev->window_if->joy_remove(dev, joystick_index);
}
}
}
void dc_joy_add(struct dreamcast *dc, int joystick_index) {
list_for_each_entry(dev, &dc->devices, struct device, it) {
if (dev->window_if && dev->window_if->joy_add) {
dev->window_if->joy_add(dev, joystick_index);
}
}
dc->client.push_audio(dc->client.userdata, data, frames);
}
void dc_keydown(struct dreamcast *dc, int device_index, enum keycode code,
@ -183,13 +189,9 @@ void dc_destroy_window_interface(struct window_interface *window) {
free(window);
}
struct window_interface *dc_create_window_interface(
device_keydown_cb keydown, device_joy_add_cb joy_add,
device_joy_remove_cb joy_remove) {
struct window_interface *dc_create_window_interface(device_keydown_cb keydown) {
struct window_interface *window = calloc(1, sizeof(struct window_interface));
window->keydown = keydown;
window->joy_add = joy_add;
window->joy_remove = joy_remove;
return window;
}

View File

@ -92,8 +92,6 @@ typedef void (*device_joy_remove_cb)(struct device *, int);
struct window_interface {
device_keydown_cb keydown;
device_joy_add_cb joy_add;
device_joy_remove_cb joy_remove;
};
/*
@ -135,12 +133,16 @@ struct device {
typedef void (*push_audio_cb)(void *, const int16_t *, int);
typedef void (*start_render_cb)(void *, struct tile_ctx *);
typedef void (*finish_render_cb)(void *);
typedef void (*poll_input_cb)(void *);
typedef int16_t (*get_input_cb)(void *, int, int);
struct dreamcast_client {
void *userdata;
push_audio_cb push_audio;
start_render_cb start_render;
finish_render_cb finish_render;
poll_input_cb poll_input;
get_input_cb get_input;
};
struct dreamcast {
@ -180,9 +182,7 @@ struct memory_interface *dc_create_memory_interface(struct dreamcast *dc,
address_map_cb mapper);
void dc_destroy_memory_interface(struct memory_interface *memory);
struct window_interface *dc_create_window_interface(
device_keydown_cb keydown, device_joy_add_cb joy_add,
device_joy_remove_cb joy_remove);
struct window_interface *dc_create_window_interface(device_keydown_cb keydown);
void dc_destroy_window_interface(struct window_interface *window);
int dc_init(struct dreamcast *dc);
@ -194,11 +194,12 @@ void dc_tick(struct dreamcast *dc, int64_t ns);
void dc_debug_menu(struct dreamcast *dc, struct nk_context *ctx);
void dc_keydown(struct dreamcast *dc, int device_index, enum keycode code,
int16_t value);
void dc_joy_add(struct dreamcast *dc, int joystick_index);
void dc_joy_remove(struct dreamcast *dc, int joystick_index);
/* client functionality */
void dc_push_audio(struct dreamcast *dc, const int16_t *data, int frames);
void dc_start_render(struct dreamcast *dc, struct tile_ctx *ctx);
void dc_finish_render(struct dreamcast *dc);
void dc_poll_input(struct dreamcast *dc);
int16_t dc_get_input(struct dreamcast *dc, int port, int button);
#endif

View File

@ -1,133 +1,38 @@
#include <ini.h>
#include "core/log.h"
#include "core/option.h"
#include "core/string.h"
#include "hw/maple/maple.h"
DEFINE_OPTION_STRING(profile, "profiles/ps4.ini", "Controller profile");
enum {
CONT_C = 0x1,
CONT_B = 0x2,
CONT_A = 0x4,
CONT_START = 0x8,
CONT_DPAD_UP = 0x10,
CONT_DPAD_DOWN = 0x20,
CONT_DPAD_LEFT = 0x40,
CONT_DPAD_RIGHT = 0x80,
CONT_Z = 0x100,
CONT_Y = 0x200,
CONT_X = 0x400,
CONT_D = 0x800,
CONT_DPAD2_UP = 0x1000,
CONT_DPAD2_DOWN = 0x2000,
CONT_DPAD2_LEFT = 0x4000,
CONT_DPAD2_RIGHT = 0x8000,
/* only used by internal button map */
CONT_JOYX = 0x10000,
CONT_JOYY = 0x20000,
CONT_LTRIG = 0x40000,
CONT_RTRIG = 0x80000
};
struct controller {
struct maple_device;
struct maple_cond cnd;
int map[K_NUM_KEYS];
};
static int controller_ini_handler(void *user, const char *section,
const char *name, const char *value) {
struct controller *ctrl = user;
static void controller_update(struct controller *ctrl) {
dc_poll_input(ctrl->dc);
int button = 0;
if (!strcmp(name, "joyx")) {
button = CONT_JOYX;
} else if (!strcmp(name, "joyy")) {
button = CONT_JOYY;
} else if (!strcmp(name, "ltrig")) {
button = CONT_LTRIG;
} else if (!strcmp(name, "rtrig")) {
button = CONT_RTRIG;
} else if (!strcmp(name, "start")) {
button = CONT_START;
} else if (!strcmp(name, "a")) {
button = CONT_A;
} else if (!strcmp(name, "b")) {
button = CONT_B;
} else if (!strcmp(name, "x")) {
button = CONT_X;
} else if (!strcmp(name, "y")) {
button = CONT_Y;
} else if (!strcmp(name, "dpad_up")) {
button = CONT_DPAD_UP;
} else if (!strcmp(name, "dpad_down")) {
button = CONT_DPAD_DOWN;
} else if (!strcmp(name, "dpad_left")) {
button = CONT_DPAD_LEFT;
} else if (!strcmp(name, "dpad_right")) {
button = CONT_DPAD_RIGHT;
} else {
LOG_WARNING("Unknown button %s", name);
return 0;
}
for (int button = 0; button < NUM_CONTROLS; button++) {
int button_mask = 1 << button;
enum keycode key = get_key_by_name(value);
if (key == K_UNKNOWN) {
LOG_WARNING("Unknown key %s", value);
return 0;
}
/* scale incoming int16_t -> uint8_t */
int16_t value = dc_get_input(ctrl->dc, ctrl->port, button);
uint8_t scaled = ((int32_t)value - INT16_MIN) >> 8;
ctrl->map[key] = button;
return 1;
}
static void controller_load_profile(struct controller *ctrl, const char *path) {
if (!*path) {
return;
}
LOG_INFO("Loading controller profile %s", path);
if (ini_parse(path, controller_ini_handler, ctrl) < 0) {
LOG_WARNING("Failed to parse %s", path);
return;
}
}
static int controller_input(struct maple_device *dev, enum keycode key,
int16_t value) {
struct controller *ctrl = (struct controller *)dev;
/* map incoming key to dreamcast button */
int button = ctrl->map[key];
/* scale incoming int16_t -> uint8_t */
uint8_t scaled = ((int32_t)value - INT16_MIN) >> 8;
if (!button) {
LOG_DEBUG("Unhandled key %s", get_name_by_key(key));
return 0;
}
if (button <= CONT_DPAD2_RIGHT) {
if (value > 0) {
ctrl->cnd.buttons &= ~button;
} else {
ctrl->cnd.buttons |= button;
if (button <= CONT_DPAD2_RIGHT) {
if (value > 0) {
ctrl->cnd.buttons &= ~button_mask;
} else {
ctrl->cnd.buttons |= button_mask;
}
} else if (button == CONT_JOYX) {
ctrl->cnd.joyx = scaled;
} else if (button == CONT_JOYY) {
ctrl->cnd.joyy = scaled;
} else if (button == CONT_LTRIG) {
ctrl->cnd.ltrig = scaled;
} else if (button == CONT_RTRIG) {
ctrl->cnd.rtrig = scaled;
}
} else if (button == CONT_JOYX) {
ctrl->cnd.joyx = scaled;
} else if (button == CONT_JOYY) {
ctrl->cnd.joyy = scaled;
} else if (button == CONT_LTRIG) {
ctrl->cnd.ltrig = scaled;
} else if (button == CONT_RTRIG) {
ctrl->cnd.rtrig = scaled;
}
return 1;
}
static int controller_frame(struct maple_device *dev,
@ -155,12 +60,15 @@ static int controller_frame(struct maple_device *dev,
}
return 1;
case MAPLE_REQ_GETCOND:
case MAPLE_REQ_GETCOND: {
controller_update(ctrl);
res->header.command = MAPLE_RES_TRANSFER;
res->header.recv_addr = frame->header.send_addr;
res->header.send_addr = frame->header.recv_addr;
res->header.num_words = sizeof(ctrl->cnd) >> 2;
memcpy(res->params, &ctrl->cnd, sizeof(ctrl->cnd));
}
return 1;
}
@ -172,12 +80,13 @@ static void controller_destroy(struct maple_device *dev) {
free(ctrl);
}
struct maple_device *controller_create(int port, int unit) {
struct maple_device *controller_create(struct dreamcast *dc, int port,
int unit) {
struct controller *ctrl = calloc(1, sizeof(struct controller));
ctrl->dc = dc;
ctrl->port = port;
ctrl->unit = unit;
ctrl->destroy = &controller_destroy;
ctrl->input = &controller_input;
ctrl->frame = &controller_frame;
/* default state */
@ -186,21 +95,5 @@ struct maple_device *controller_create(int port, int unit) {
ctrl->cnd.rtrig = ctrl->cnd.ltrig = 0;
ctrl->cnd.joyy = ctrl->cnd.joyx = ctrl->cnd.joyx2 = ctrl->cnd.joyy2 = 0x80;
/* default profile */
ctrl->map[K_SPACE] = CONT_START;
ctrl->map['k'] = CONT_A;
ctrl->map['l'] = CONT_B;
ctrl->map['j'] = CONT_X;
ctrl->map['i'] = CONT_Y;
ctrl->map['w'] = CONT_DPAD_UP;
ctrl->map['s'] = CONT_DPAD_DOWN;
ctrl->map['a'] = CONT_DPAD_LEFT;
ctrl->map['d'] = CONT_DPAD_RIGHT;
ctrl->map['o'] = CONT_LTRIG;
ctrl->map['p'] = CONT_RTRIG;
/* load profile */
controller_load_profile(ctrl, OPTION_profile);
return (struct maple_device *)ctrl;
}

View File

@ -3,9 +3,6 @@
#include "hw/holly/holly.h"
#include "hw/sh4/sh4.h"
#define MAPLE_NUM_PORTS 4
#define MAPLE_MAX_UNITS 6
struct maple {
struct device;
struct maple_device *devices[MAPLE_NUM_PORTS][MAPLE_MAX_UNITS];
@ -27,64 +24,21 @@ static void maple_unregister_device(struct maple *mp, int port, int unit) {
static void maple_register_device(struct maple *mp, const char *device_type,
int port, int unit) {
struct dreamcast *dc = mp->dc;
CHECK(!mp->devices[port][unit],
"Device already registered for port %d, unit %d", port, unit);
struct maple_device **dev = &mp->devices[port][unit];
if (!strcmp(device_type, "controller")) {
*dev = controller_create(port, unit);
*dev = controller_create(dc, port, unit);
} else if (!strcmp(device_type, "vmu")) {
*dev = vmu_create(port, unit);
*dev = vmu_create(dc, port, unit);
} else {
LOG_WARNING("Unsupported device type: %s", device_type);
}
}
void maple_joy_add(struct device *data, int joystick_index) {
struct maple *mp = (struct maple *)data;
/* ignore out of range events or events for the default controller which is
always connected */
if (joystick_index <= 0 || joystick_index >= MAPLE_NUM_PORTS) {
return;
}
/* attach joystick to the corresponding maple port */
maple_register_device(mp, "controller", joystick_index, 0);
}
void maple_joy_remove(struct device *data, int joystick_index) {
struct maple *mp = (struct maple *)data;
/* ignore out of range events or events for the default controller which is
always connected */
if (joystick_index <= 0 || joystick_index >= MAPLE_NUM_PORTS) {
return;
}
/* remove all units from the corresponding maple port */
for (int i = 0; i < MAPLE_MAX_UNITS; i++) {
maple_unregister_device(mp, joystick_index, i);
}
}
static void maple_keydown(struct device *d, int device_index, enum keycode key,
int16_t value) {
if (device_index >= MAPLE_NUM_PORTS) {
return;
}
struct maple *mp = (struct maple *)d;
for (int i = 0; i < MAPLE_MAX_UNITS; i++) {
struct maple_device *dev = mp->devices[device_index][i];
if (dev && dev->input) {
dev->input(dev, key, value);
}
}
}
/* on each maple port, there are up to 6 addressable units. there is one main
unit (controller, keyboard, etc.) that can have up to 5 sub-units connected
to it (vmu, microphone, etc.). each maple frame header contains an 8-bit
@ -168,19 +122,18 @@ void maple_destroy(struct maple *mp) {
}
}
dc_destroy_window_interface(mp->window_if);
dc_destroy_device((struct device *)mp);
}
struct maple *maple_create(struct dreamcast *dc) {
struct maple *mp =
dc_create_device(dc, sizeof(struct maple), "maple", &maple_init, NULL);
mp->window_if = dc_create_window_interface(&maple_keydown, &maple_joy_add,
&maple_joy_remove);
/* add one controller and vmu by default */
maple_register_device(mp, "controller", 0, 0);
maple_register_device(mp, "vmu", 0, 1);
/* register a controller and vmu for all ports by default */
for (int i = 0; i < MAPLE_NUM_PORTS; i++) {
maple_register_device(mp, "controller", i, 0);
maple_register_device(mp, "vmu", i, 1);
}
return mp;
}

View File

@ -3,17 +3,16 @@
#include "hw/dreamcast.h"
#include "hw/maple/maple_types.h"
#include "ui/keycode.h"
struct dreamcast;
struct maple;
struct maple_device;
struct maple_device {
struct dreamcast *dc;
int port;
int unit;
void (*destroy)(struct maple_device *);
int (*input)(struct maple_device *, enum keycode, int16_t);
int (*frame)(struct maple_device *, const struct maple_frame *,
struct maple_frame *);
};
@ -24,7 +23,8 @@ void maple_destroy(struct maple *mp);
int maple_handle_command(struct maple *mp, struct maple_frame *frame,
struct maple_frame *res);
struct maple_device *controller_create(int port, int unit);
struct maple_device *vmu_create(int port, int unit);
struct maple_device *controller_create(struct dreamcast *dc, int port,
int unit);
struct maple_device *vmu_create(struct dreamcast *dc, int port, int unit);
#endif

View File

@ -1,6 +1,9 @@
#ifndef MAPLE_TYPES_H
#define MAPLE_TYPES_H
#define MAPLE_NUM_PORTS 4
#define MAPLE_MAX_UNITS 6
/* maple pattern codes. indicate how to process the incoming instruction */
enum maple_pattern {
MAPLE_PATTERN_NORMAL = 0x0,
@ -133,4 +136,30 @@ struct maple_blockread {
uint32_t data[];
};
/* controller buttons */
enum {
CONT_C,
CONT_B,
CONT_A,
CONT_START,
CONT_DPAD_UP,
CONT_DPAD_DOWN,
CONT_DPAD_LEFT,
CONT_DPAD_RIGHT,
CONT_Z,
CONT_Y,
CONT_X,
CONT_D,
CONT_DPAD2_UP,
CONT_DPAD2_DOWN,
CONT_DPAD2_LEFT,
CONT_DPAD2_RIGHT,
/* only used by internal button map */
CONT_JOYX,
CONT_JOYY,
CONT_LTRIG,
CONT_RTRIG,
NUM_CONTROLS,
};
#endif

View File

@ -184,8 +184,9 @@ static void vmu_destroy(struct maple_device *dev) {
free(vmu);
}
struct maple_device *vmu_create(int port, int unit) {
struct maple_device *vmu_create(struct dreamcast *dc, int port, int unit) {
struct vmu *vmu = calloc(1, sizeof(struct vmu));
vmu->dc = dc;
vmu->port = port;
vmu->unit = unit;
vmu->destroy = &vmu_destroy;

View File

@ -854,7 +854,7 @@ struct tracer *tracer_create(struct window *win) {
/* add window input listeners */
tracer->listener = (struct window_listener){
tracer, NULL, NULL, &tracer_keydown, NULL, &tracer_close, {0}};
tracer, &tracer_keydown, NULL, &tracer_close, {0}};
win_add_listener(tracer->win, &tracer->listener);
/* setup render backend */

View File

@ -275,7 +275,7 @@ struct microprofile *mp_create(struct window *win, struct render_backend *r) {
mp->r = r;
/* add input event listeners */
mp->listener = {mp, NULL, NULL, &mp_keydown, &mp_mousemove, NULL, {}};
mp->listener = {mp, &mp_keydown, &mp_mousemove, NULL, {}};
win_add_listener(mp->win, &mp->listener);
/* register and enable cpu and gpu groups by default */

View File

@ -151,8 +151,8 @@ struct nuklear *nk_create(struct window *win, struct render_backend *r) {
nk->r = r;
/* add input event listeners */
nk->listener = (struct window_listener){
nk, NULL, NULL, &nk_keydown, &nk_mousemove, NULL, {0}};
nk->listener =
(struct window_listener){nk, &nk_keydown, &nk_mousemove, NULL, {0}};
win_add_listener(nk->win, &nk->listener);
/* create default font texture */

View File

@ -12,8 +12,6 @@ typedef void *glcontext_t;
struct window_listener {
void *data;
void (*joy_add)(void *data, int joystick_index);
void (*joy_remove)(void *data, int joystick_index);
void (*keydown)(void *data, int device_index, enum keycode code,
int16_t value);
void (*mousemove)(void *data, int x, int y);

View File

@ -45,13 +45,6 @@ static void win_destroy_joystick(struct window *win, SDL_Joystick *del) {
SDL_JoystickClose(*joy);
*joy = NULL;
/* inform listeners */
list_for_each_entry(listener, &win->listeners, struct window_listener, it) {
if (listener->joy_remove) {
listener->joy_remove(listener->data, i);
}
}
break;
}
}
@ -75,13 +68,6 @@ static void win_create_joystick(struct window *win, int joystick_index) {
/* reset state */
memset(win->hat_state[i], 0, sizeof(win->hat_state[i]));
/* inform listeners */
list_for_each_entry(listener, &win->listeners, struct window_listener, it) {
if (listener->joy_add) {
listener->joy_add(listener->data, joystick_index);
}
}
break;
}
}