diff --git a/src/emulator.c b/src/emulator.c index e373464b..6c11d166 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -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 */ diff --git a/src/hw/dreamcast.c b/src/hw/dreamcast.c index fde705b4..0a08d173 100644 --- a/src/hw/dreamcast.c +++ b/src/hw/dreamcast.c @@ -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; } diff --git a/src/hw/dreamcast.h b/src/hw/dreamcast.h index 499cc281..323062b7 100644 --- a/src/hw/dreamcast.h +++ b/src/hw/dreamcast.h @@ -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 diff --git a/src/hw/maple/controller.c b/src/hw/maple/controller.c index 78f0ef31..15ece043 100644 --- a/src/hw/maple/controller.c +++ b/src/hw/maple/controller.c @@ -1,133 +1,38 @@ -#include -#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; } diff --git a/src/hw/maple/maple.c b/src/hw/maple/maple.c index b11b4a17..316d978b 100644 --- a/src/hw/maple/maple.c +++ b/src/hw/maple/maple.c @@ -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; } diff --git a/src/hw/maple/maple.h b/src/hw/maple/maple.h index 094f4f83..a9951602 100644 --- a/src/hw/maple/maple.h +++ b/src/hw/maple/maple.h @@ -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 diff --git a/src/hw/maple/maple_types.h b/src/hw/maple/maple_types.h index 7ad39b50..33a96874 100644 --- a/src/hw/maple/maple_types.h +++ b/src/hw/maple/maple_types.h @@ -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 diff --git a/src/hw/maple/vmu.c b/src/hw/maple/vmu.c index 2be674a7..a750c638 100644 --- a/src/hw/maple/vmu.c +++ b/src/hw/maple/vmu.c @@ -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; diff --git a/src/tracer.c b/src/tracer.c index 4c8f5d32..7e6bc794 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -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 */ diff --git a/src/ui/microprofile.cc b/src/ui/microprofile.cc index 3af29d82..84a437a9 100644 --- a/src/ui/microprofile.cc +++ b/src/ui/microprofile.cc @@ -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 */ diff --git a/src/ui/nuklear.c b/src/ui/nuklear.c index e25bf598..1bd00dc6 100644 --- a/src/ui/nuklear.c +++ b/src/ui/nuklear.c @@ -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 */ diff --git a/src/ui/window.h b/src/ui/window.h index 218ac5c0..34b03edd 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -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); diff --git a/src/ui/window_sdl.c b/src/ui/window_sdl.c index 138b5db7..ef6174d5 100644 --- a/src/ui/window_sdl.c +++ b/src/ui/window_sdl.c @@ -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; } }