summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--controller_info.c125
-rw-r--r--controller_info.h45
-rw-r--r--nuklear_ui/blastem_nuklear.c47
-rwxr-xr-xrender_sdl.c16
-rw-r--r--render_sdl.h3
6 files changed, 231 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 040b6db..58dbf59 100644
--- a/Makefile
+++ b/Makefile
@@ -136,7 +136,7 @@ endif
Z80OBJS=z80inst.o z80_to_x86.o
AUDIOOBJS=ym2612.o psg.o wave.o
CONFIGOBJS=config.o tern.o util.o paths.o
-NUKLEAROBJS=$(FONT) nuklear_ui/blastem_nuklear.o nuklear_ui/sfnt.o
+NUKLEAROBJS=$(FONT) nuklear_ui/blastem_nuklear.o nuklear_ui/sfnt.o controller_info.o
RENDEROBJS=render_sdl.o ppm.o
LIBZOBJS=zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/gzclose.o zlib/gzlib.o zlib/gzread.o\
zlib/gzwrite.o zlib/infback.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o zlib/uncompr.o zlib/zutil.o
diff --git a/controller_info.c b/controller_info.c
new file mode 100644
index 0000000..1001c97
--- /dev/null
+++ b/controller_info.c
@@ -0,0 +1,125 @@
+#include <string.h>
+#include "render_sdl.h"
+#include "controller_info.h"
+
+typedef struct {
+ char const *name;
+ controller_info info;
+} heuristic;
+
+heuristic heuristics[] = {
+ //TODO: Add more heuristic rules
+ {"DualShock 4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
+ {"PS4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
+ {"PS3", {.type = TYPE_PSX, .subtype = SUBTYPE_PS3}},
+ {"X360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
+ {"Xbox 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
+ {"X-box 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
+ {"Xbox One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
+ {"X-box One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
+ {"WiiU", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
+ {"Wii U", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
+ {"Nintendo Switch", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_SWITCH}},
+ {"Saturn", {.type = TYPE_SEGA, .subtype = SUBTYPE_SATURN}}
+};
+const uint32_t num_heuristics = sizeof(heuristics)/sizeof(*heuristics);
+
+controller_info get_controller_info(int joystick)
+{
+ SDL_GameController *control = render_get_controller(joystick);
+ if (!control) {
+ return (controller_info) {
+ .type = TYPE_UNKNOWN,
+ .subtype = SUBTYPE_UNKNOWN,
+ .variant = VARIANT_NORMAL,
+ .name = SDL_JoystickName(render_get_joystick(joystick))
+ };
+ }
+ const char *name = SDL_GameControllerName(control);
+ SDL_GameControllerClose(control);
+ for (uint32_t i = 0; i < num_heuristics; i++)
+ {
+ if (strstr(name, heuristics[i].name)) {
+ controller_info res = heuristics[i].info;
+ res.name = name;
+ return res;
+ }
+ }
+ //default to a 360
+ return (controller_info){
+ .type = TYPE_GENERIC_MAPPING,
+ .subtype = SUBTYPE_UNKNOWN,
+ .variant = VARIANT_NORMAL,
+ .name = name
+ };
+}
+
+char const *labels_xbox[] = {
+ "A", "B", "X", "Y", "Back", NULL, "Start", "Click", "Click", "White", "Black", "LT", "RT"
+};
+char const *labels_360[] = {
+ "A", "B", "X", "Y", "Back", "Guide", "Start", "Click", "Click", "LB", "RB", "LT", "RT"
+};
+static char const *labels_xbone[] = {
+ "A", "B", "X", "Y", "View", "Guide", "Menu", "Click", "Click", "LB", "RB", "LT", "RT"
+};
+static char const *labels_ps3[] = {
+ "cross", "circle", "square", "triangle", "Select", "Guide", "Start", "L3", "R3", "L1", "R1", "L2", "R2"
+};
+static char const *labels_ps4[] = {
+ "cross", "circle", "square", "triangle", "Share", "Guide", "Options", "L3", "R3", "L1", "R1", "L2", "R2"
+};
+static char const *labels_nintendo[] = {
+ "B", "A", "Y", "X", "-", "Home", "+", "Click", "Click", "L", "R", "ZL", "ZR"
+};
+static char const *labels_genesis[] = {
+ "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", NULL, "Mode"
+};
+static char const *labels_saturn[] = {
+ "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", "LT", "RT"
+};
+
+static const char** label_source(controller_info *info)
+{
+ if (info->type == TYPE_UNKNOWN || info->type == TYPE_GENERIC_MAPPING || info->subtype ==SUBTYPE_X360) {
+ return labels_360;
+ } else if (info->type == TYPE_NINTENDO) {
+ return labels_nintendo;
+ } else if (info->type == TYPE_PSX) {
+ if (info->subtype == SUBTYPE_PS4) {
+ return labels_ps4;
+ } else {
+ return labels_ps3;
+ }
+ } else if (info->type == TYPE_XBOX) {
+ if (info->subtype == SUBTYPE_XBONE) {
+ return labels_xbone;
+ } else {
+ return labels_xbox;
+ }
+ } else {
+ if (info->subtype == SUBTYPE_GENESIS) {
+ return labels_genesis;
+ } else {
+ return labels_saturn;
+ }
+ }
+}
+
+const char *get_button_label(controller_info *info, int button)
+{
+ return label_source(info)[button];
+}
+
+static char const *axis_labels[] = {
+ "Left X", "Left Y", "Right X", "Right Y"
+};
+const char *get_axis_label(controller_info *info, int axis)
+{
+ if (axis < SDL_CONTROLLER_AXIS_TRIGGERLEFT) {
+ return axis_labels[axis];
+ } else {
+ return label_source(info)[axis - SDL_CONTROLLER_AXIS_TRIGGERLEFT + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER + 1];
+ }
+}
+
diff --git a/controller_info.h b/controller_info.h
new file mode 100644
index 0000000..0bef684
--- /dev/null
+++ b/controller_info.h
@@ -0,0 +1,45 @@
+#ifndef CONTROLLER_INFO_H_
+#define CONTROLLER_INFO_H_
+#include <stdint.h>
+
+enum {
+ TYPE_UNKNOWN,
+ TYPE_GENERIC_MAPPING,
+ TYPE_XBOX,
+ TYPE_PSX,
+ TYPE_NINTENDO,
+ TYPE_SEGA
+};
+
+enum {
+ SUBTYPE_UNKNOWN,
+ SUBTYPE_XBOX,
+ SUBTYPE_X360,
+ SUBTYPE_XBONE,
+ SUBTYPE_PS2,
+ SUBTYPE_PS3,
+ SUBTYPE_PS4,
+ SUBTYPE_WIIU,
+ SUBTYPE_SWITCH,
+ SUBTYPE_GENESIS,
+ SUBTYPE_SATURN
+};
+
+enum {
+ VARIANT_NORMAL,
+ VARIANT_6B_BUMPERS, //C and Z positions are RB and LB respectively
+ VARIANT_6B_RIGHT //C and Z positions are RT and RB respectively
+};
+
+typedef struct {
+ char const *name;
+ uint8_t type;
+ uint8_t subtype;
+ uint8_t variant;
+} controller_info;
+
+controller_info get_controller_info(int index);
+const char *get_button_label(controller_info *info, int button);
+const char *get_axis_label(controller_info *info, int axis);
+
+#endif //CONTROLLER_INFO_H_ \ No newline at end of file
diff --git a/nuklear_ui/blastem_nuklear.c b/nuklear_ui/blastem_nuklear.c
index d347e54..cd550a9 100644
--- a/nuklear_ui/blastem_nuklear.c
+++ b/nuklear_ui/blastem_nuklear.c
@@ -14,6 +14,7 @@
#include "../config.h"
#include "../io.h"
#include "../png.h"
+#include "../controller_info.h"
static struct nk_context *context;
@@ -500,11 +501,14 @@ void view_key_bindings(struct nk_context *context)
nk_end(context);
}
}
+
+static int selected_controller;
+static controller_info selected_controller_info;
static struct nk_image controller_360_image;
static uint32_t controller_360_width, controller_360_height;
//#define MIN_BIND_BOX_WIDTH 140
#define MAX_BIND_BOX_WIDTH 350
-void view_controllers(struct nk_context *context)
+void view_controller_bindings(struct nk_context *context)
{
if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
float orig_height = def_font->handle.height;
@@ -554,13 +558,13 @@ void view_controllers(struct nk_context *context)
nk_group_begin(context, "Action Buttons", NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR);
float widths[] = {34, bind_box_width - 60};
nk_layout_row(context, NK_STATIC, 34, 2, widths);
- nk_label(context, "A", NK_TEXT_LEFT);
+ nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_A), NK_TEXT_LEFT);
nk_button_label(context, "A");
- nk_label(context, "B", NK_TEXT_LEFT);
+ nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_B), NK_TEXT_LEFT);
nk_button_label(context, "B");
- nk_label(context, "X", NK_TEXT_LEFT);
+ nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_X), NK_TEXT_LEFT);
nk_button_label(context, "X");
- nk_label(context, "Y", NK_TEXT_LEFT);
+ nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_Y), NK_TEXT_LEFT);
nk_button_label(context, "Internal Screenshot");
nk_group_end(context);
@@ -578,7 +582,7 @@ void view_controllers(struct nk_context *context)
nk_button_label(context, "Left");
nk_label(context, "Right", NK_TEXT_LEFT);
nk_button_label(context, "Right");
- nk_label(context, "Click", NK_TEXT_LEFT);
+ nk_label(context, get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_LEFTSTICK), NK_TEXT_LEFT);
nk_button_label(context, "None");
nk_group_end(context);
@@ -594,6 +598,37 @@ void view_controllers(struct nk_context *context)
}
}
+void view_controllers(struct nk_context *context)
+{
+ if (nk_begin(context, "Controllers", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
+ int height = (render_width() - 2*context->style.font->height) / MAX_JOYSTICKS;
+ int image_width = height * controller_360_width / controller_360_height;
+ for (int i = 0; i < MAX_JOYSTICKS; i++)
+ {
+ SDL_Joystick *joy = render_get_joystick(i);
+ if (joy) {
+ controller_info info = get_controller_info(i);
+ nk_layout_row_begin(context, NK_STATIC, height, 2);
+ nk_layout_row_push(context, image_width);
+ nk_image(context, controller_360_image);
+ nk_layout_row_push(context, render_width() - image_width - 2 * context->style.font->height);
+ if (nk_button_label(context, info.name)) {
+ selected_controller = i;
+ selected_controller_info = info;
+ push_view(view_controller_bindings);
+ }
+ nk_layout_row_end(context);
+ }
+ }
+ nk_layout_row_static(context, context->style.font->height, (render_width() - 2 * context->style.font->height) / 2, 2);
+ nk_label(context, "", NK_TEXT_LEFT);
+ if (nk_button_label(context, "Back")) {
+ pop_view();
+ }
+ nk_end(context);
+ }
+}
+
void settings_toggle(struct nk_context *context, char *label, char *path, uint8_t def)
{
uint8_t curval = !strcmp("on", tern_find_path_default(config, path, (tern_val){.ptrval = def ? "on": "off"}, TVAL_PTR).ptrval);
diff --git a/render_sdl.c b/render_sdl.c
index 3296581..1c9aecf 100755
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -805,6 +805,22 @@ static int lowest_unused_joystick_index()
return -1;
}
+SDL_Joystick *render_get_joystick(int index)
+{
+ if (index >= MAX_JOYSTICKS) {
+ return NULL;
+ }
+ return joysticks[index];
+}
+
+SDL_GameController *render_get_controller(int index)
+{
+ if (index >= MAX_JOYSTICKS) {
+ return NULL;
+ }
+ return SDL_GameControllerOpen(joystick_sdl_index[index]);
+}
+
static uint32_t overscan_top[NUM_VID_STD] = {2, 21};
static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
static uint32_t overscan_left[NUM_VID_STD] = {13, 13};
diff --git a/render_sdl.h b/render_sdl.h
index 3aa54e6..db50c86 100644
--- a/render_sdl.h
+++ b/render_sdl.h
@@ -10,5 +10,8 @@ void render_update_display(void);
void render_set_ui_render_fun(ui_render_fun);
void render_set_event_handler(event_handler handler);
void render_set_gl_context_handlers(ui_render_fun destroy, ui_render_fun create);
+SDL_Joystick *render_get_joystick(int index);
+SDL_GameController *render_get_controller(int index);
+
#endif //RENDER_SDL_H_