# HG changeset patch # User Michael Pavone # Date 1540440612 25200 # Node ID 18a946ec74c89009846ab3251992fb9137c5200b # Parent 4bb2c8b78b4ab0289ca308114346e44131e0a60c Pull current controller config in binding UI from whatever the actual binding code would end up using diff -r 4bb2c8b78b4a -r 18a946ec74c8 bindings.c --- a/bindings.c Tue Oct 09 09:29:28 2018 -0700 +++ b/bindings.c Wed Oct 24 21:10:12 2018 -0700 @@ -857,72 +857,78 @@ return mousebuttons; } -void handle_joy_added(int joystick) +tern_node *get_binding_node_for_pad(int padnum) { - if (joystick > MAX_JOYSTICKS) { - return; + if (padnum > MAX_JOYSTICKS) { + return NULL; } tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval; - if (pads) { - char numstr[11]; - sprintf(numstr, "%d", joystick); - tern_node * pad = tern_find_node(pads, numstr); - if (!pad) { - char *type_id = render_joystick_type_id(joystick); - pad = tern_find_node(pads, type_id); - free(type_id); - } - if (!pad) { - controller_info info = get_controller_info(joystick); - char *key = make_controller_type_key(&info); - pad = tern_find_node(pads, key); - free(key); - } - if (!pad) { - pad = tern_find_node(pads, "default"); - } - if (pad) { - tern_node * dpad_node = tern_find_node(pad, "dpads"); - if (dpad_node) { - for (int dpad = 0; dpad < 10; dpad++) - { - numstr[0] = dpad + '0'; - numstr[1] = 0; - tern_node * pad_dpad = tern_find_node(dpad_node, numstr); - char * dirs[] = {"up", "down", "left", "right"}; - //TODO: Support controllers that have d-pads implemented as analog axes or buttons - int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; - for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { - char * target = tern_find_ptr(pad_dpad, dirs[dir]); - if (target) { - uint8_t subtype_a = 0, subtype_b = 0; - int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b); - bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b); - } - } + if (!pads) { + return NULL; + } + char numstr[11]; + sprintf(numstr, "%d", padnum); + tern_node * pad = tern_find_node(pads, numstr); + if (!pad) { + char *type_id = render_joystick_type_id(padnum); + pad = tern_find_node(pads, type_id); + free(type_id); + } + if (!pad) { + controller_info info = get_controller_info(padnum); + char *key = make_controller_type_key(&info); + pad = tern_find_node(pads, key); + free(key); + } + if (!pad) { + pad = tern_find_node(pads, "default"); + } + return pad; +} + +void handle_joy_added(int joystick) +{ + tern_node *pad = get_binding_node_for_pad(joystick); + if (!pad) { + return; + } + tern_node * dpad_node = tern_find_node(pad, "dpads"); + if (dpad_node) { + for (int dpad = 0; dpad < 10; dpad++) + { + char numstr[2] = {dpad + '0', 0}; + tern_node * pad_dpad = tern_find_node(dpad_node, numstr); + char * dirs[] = {"up", "down", "left", "right"}; + //TODO: Support controllers that have d-pads implemented as analog axes or buttons + int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; + for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { + char * target = tern_find_ptr(pad_dpad, dirs[dir]); + if (target) { + uint8_t subtype_a = 0, subtype_b = 0; + int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b); + bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b); } } - tern_node *button_node = tern_find_node(pad, "buttons"); - if (button_node) { - pad_button_state state = { - .padnum = joystick, - .padbuttons = get_pad_buttons(), - .mousebuttons = get_mouse_buttons() - }; - tern_foreach(button_node, process_pad_button, &state); - } - tern_node *axes_node = tern_find_node(pad, "axes"); - if (axes_node) { - pad_button_state state = { - .padnum = joystick, - .padbuttons = get_pad_buttons(), - .mousebuttons = get_mouse_buttons() - }; - tern_foreach(axes_node, process_pad_axis, &state); - } } } - + tern_node *button_node = tern_find_node(pad, "buttons"); + if (button_node) { + pad_button_state state = { + .padnum = joystick, + .padbuttons = get_pad_buttons(), + .mousebuttons = get_mouse_buttons() + }; + tern_foreach(button_node, process_pad_button, &state); + } + tern_node *axes_node = tern_find_node(pad, "axes"); + if (axes_node) { + pad_button_state state = { + .padnum = joystick, + .padbuttons = get_pad_buttons(), + .mousebuttons = get_mouse_buttons() + }; + tern_foreach(axes_node, process_pad_axis, &state); + } } //only handles keyboards and mice as gamepads are handled on hotplug events diff -r 4bb2c8b78b4a -r 18a946ec74c8 bindings.h --- a/bindings.h Tue Oct 09 09:29:28 2018 -0700 +++ b/bindings.h Wed Oct 24 21:10:12 2018 -0700 @@ -11,6 +11,7 @@ void set_bindings(void); void bindings_set_mouse_mode(uint8_t mode); +tern_node *get_binding_node_for_pad(int padnum); void handle_keydown(int keycode, uint8_t scancode); void handle_keyup(int keycode, uint8_t scancode); void handle_joydown(int joystick, int button); diff -r 4bb2c8b78b4a -r 18a946ec74c8 nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Tue Oct 09 09:29:28 2018 -0700 +++ b/nuklear_ui/blastem_nuklear.c Wed Oct 24 21:10:12 2018 -0700 @@ -15,6 +15,7 @@ #include "../io.h" #include "../png.h" #include "../controller_info.h" +#include "../bindings.h" static struct nk_context *context; @@ -514,7 +515,7 @@ #define LEFTSTICK 0x10000000 #define RIGHTSTICK 0x20000000 enum { - UP,DOWN,LEFT,RIGHT + UP,DOWN,RIGHT,LEFT,NUM_AXIS_DIRS }; static char * config_ps_names[] = { @@ -530,71 +531,35 @@ [SDL_CONTROLLER_BUTTON_RIGHTSTICK] = "r3", }; -static void binding_box(struct nk_context *context, char *name, float x, float y, float width, int num_binds, int *binds) +typedef struct { + const char *button_binds[SDL_CONTROLLER_BUTTON_MAX]; + const char *left_stick[NUM_AXIS_DIRS]; + const char *right_stick[NUM_AXIS_DIRS]; + const char *triggers[2]; +} pad_bind_config; + +static void binding_box(struct nk_context *context, pad_bind_config *bindings, char *name, float x, float y, float width, int num_binds, int *binds) { const struct nk_user_font *font = context->style.font; float row_height = font->height * 2; char const **labels = calloc(sizeof(char *), num_binds); - char **conf_keys = calloc(sizeof(char *), num_binds); + char const **conf_vals = calloc(sizeof(char *), num_binds); float max_width = 0.0f; - static const char base_path[] = "bindings\0pads"; - static const char buttons[] = "buttons"; - static const char dpads[] = "dpads\00"; - static const char axes[] = "axes"; - static const char positive[] = ".positive"; - static const char negative[] = ".negative"; - char padkey[] = {'0' + selected_controller, 0}; int skipped = 0; for (int i = 0; i < num_binds; i++) { if (binds[i] & AXIS) { labels[i] = get_axis_label(&selected_controller_info, binds[i] & ~AXIS); - const char *axname = SDL_GameControllerGetStringForAxis(binds[i] & ~AXIS); - size_t namelen = strlen(axname); - conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + 2); - memcpy(conf_keys[i], base_path, sizeof(base_path)); - memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey)); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), axes, sizeof(axes)); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes), axname, namelen+1); - conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + 1] = 0; + conf_vals[i] = bindings->triggers[(binds[i] & ~AXIS) - SDL_CONTROLLER_AXIS_TRIGGERLEFT]; } else if (binds[i] & STICKDIR) { - static char const * dirs[] = {"Up", "Down", "Left", "Right"}; + static char const * dirs[] = {"Up", "Down", "Right", "Left"}; labels[i] = dirs[binds[i] & 3]; - uint8_t is_pos = (binds[i] & 3) == 3 || !(binds[i] & 3); - int sdl_axis = (binds[i] & LEFTSTICK ? SDL_CONTROLLER_AXIS_LEFTX : SDL_CONTROLLER_AXIS_RIGHTX) + !(binds[i] & 2); - const char *axname = SDL_GameControllerGetStringForAxis(sdl_axis); - size_t namelen = strlen(axname); - conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + sizeof(positive) + 1); - memcpy(conf_keys[i], base_path, sizeof(base_path)); - memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey)); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), axes, sizeof(axes)); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes), axname, namelen); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen, is_pos ? positive : negative, sizeof(positive)); - conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(axes) + namelen + sizeof(positive)] = 0; + conf_vals[i] = (binds[i] & LEFTSTICK ? bindings->left_stick : bindings->right_stick)[binds[i] & 3]; } else { labels[i] = get_button_label(&selected_controller_info, binds[i]); - static const char* dpdirs[] = {"up", "down", "left", "right"}; - const char *but_name, *mid; - size_t midsz; - if (binds[i] < SDL_CONTROLLER_BUTTON_DPAD_UP) { - but_name = SDL_GameControllerGetStringForButton(binds[i]); - mid = buttons; - midsz = sizeof(buttons); - } else { - but_name = dpdirs[binds[i] - SDL_CONTROLLER_BUTTON_DPAD_UP]; - mid = dpads; - midsz = sizeof(dpads); - } - size_t namelen = strlen(but_name); - conf_keys[i] = malloc(sizeof(base_path) + sizeof(padkey) + midsz + namelen + 2); - memcpy(conf_keys[i], base_path, sizeof(base_path)); - memcpy(conf_keys[i] + sizeof(base_path), padkey, sizeof(padkey)); - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey), mid, midsz); - - memcpy(conf_keys[i] + sizeof(base_path) + sizeof(padkey) + midsz, but_name, namelen+1); - conf_keys[i][sizeof(base_path) + sizeof(padkey) + sizeof(buttons) + namelen + 1] = 0; + conf_vals[i] = bindings->button_binds[binds[i]]; } if (!labels[i]) { skipped++; @@ -614,25 +579,74 @@ continue; } nk_label(context, labels[i], NK_TEXT_LEFT); - if (conf_keys[i]) { - char *assigned = tern_find_path(config, conf_keys[i], TVAL_PTR).ptrval; - if (!assigned) { - assigned = "None"; - } else if (!memcmp("gamepads.", assigned, strlen("gamepads."))) { - assigned += strlen("gamepads.0."); - } - nk_button_label(context, assigned); - } else { - nk_button_label(context, i & 1 ? "Internal Screenshot" : "A"); - } - free(conf_keys[i]); + nk_button_label(context, conf_vals[i] ? conf_vals[i] : "None"); + } + free(labels); + free(conf_vals); + nk_group_end(context); +} + +static void button_iter(char *key, tern_val val, uint8_t valtype, void *data) +{ + pad_bind_config *bindings = data; + if (valtype != TVAL_PTR) { + return; + } + int button = render_lookup_button(key); + if (button != SDL_CONTROLLER_BUTTON_INVALID) { + bindings->button_binds[button] = val.ptrval; + } +} + +static void axis_iter(char *key, tern_val val, uint8_t valtype, void *data) +{ + pad_bind_config *bindings = data; + if (valtype != TVAL_PTR) { + return; } - nk_group_end(context); + int axis; + uint8_t is_negative = 0; + char *period = strchr(key, '.'); + if (period) { + char *tmp = malloc(period-key + 1); + memcpy(tmp, key, period-key); + tmp[period-key] = 0; + axis = render_lookup_axis(key); + free(tmp); + is_negative = strcmp(period+1, "negative") == 0; + } else { + axis = render_lookup_axis(key); + } + switch (axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + case SDL_CONTROLLER_AXIS_LEFTY: + bindings->left_stick[(axis - SDL_CONTROLLER_AXIS_LEFTX) * 2 + is_negative] = val.ptrval; + break; + case SDL_CONTROLLER_AXIS_RIGHTX: + case SDL_CONTROLLER_AXIS_RIGHTY: + bindings->right_stick[(axis - SDL_CONTROLLER_AXIS_RIGHTX) * 2 + is_negative] = val.ptrval; + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + bindings->triggers[axis-SDL_CONTROLLER_AXIS_TRIGGERLEFT] = val.ptrval; + break; + } } void view_controller_bindings(struct nk_context *context) { + static pad_bind_config *bindings; if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) { + if (!bindings) { + bindings = calloc(1, sizeof(*bindings)); + tern_node *pad = get_binding_node_for_pad(selected_controller); + if (pad) { + tern_foreach(tern_find_node(pad, "buttons"), button_iter, bindings); + tern_foreach(tern_find_node(pad, "axes"), axis_iter, bindings); + } + } + float orig_height = def_font->handle.height; def_font->handle.height *= 0.5f; @@ -686,25 +700,25 @@ bind_box_left = img_right + (render_width() - img_right) / 2.0f - bind_box_width / 2.0f; } - binding_box(context, "Action Buttons", bind_box_left, img_top, bind_box_width, 4, (int[]){ + binding_box(context, bindings, "Action Buttons", bind_box_left, img_top, bind_box_width, 4, (int[]){ SDL_CONTROLLER_BUTTON_A, SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_BUTTON_Y }); - binding_box(context, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){ + binding_box(context, bindings, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, AXIS | SDL_CONTROLLER_AXIS_TRIGGERRIGHT }); - binding_box(context, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){ + binding_box(context, bindings, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){ SDL_CONTROLLER_BUTTON_BACK, SDL_CONTROLLER_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_START }); - binding_box(context, "Right Stick", img_right - desired_width/3, img_bot, bind_box_width, 5, (int[]){ + binding_box(context, bindings, "Right Stick", img_right - desired_width/3, img_bot, bind_box_width, 5, (int[]){ RIGHTSTICK | UP, RIGHTSTICK | DOWN, RIGHTSTICK | LEFT, @@ -714,7 +728,7 @@ bind_box_left -= img_right; - binding_box(context, "Left Stick", bind_box_left, img_top, bind_box_width, 5, (int[]){ + binding_box(context, bindings, "Left Stick", bind_box_left, img_top, bind_box_width, 5, (int[]){ LEFTSTICK | UP, LEFTSTICK | DOWN, LEFTSTICK | LEFT, @@ -722,12 +736,12 @@ SDL_CONTROLLER_BUTTON_LEFTSTICK }); - binding_box(context, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){ + binding_box(context, bindings, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){ SDL_CONTROLLER_BUTTON_LEFTSHOULDER, AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT }); - binding_box(context, "D-pad", img_left - desired_width/6, img_bot + font->height * 1.5, bind_box_width, 4, (int[]){ + binding_box(context, bindings, "D-pad", img_left - desired_width/6, img_bot + font->height * 1.5, bind_box_width, 4, (int[]){ SDL_CONTROLLER_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_LEFT, diff -r 4bb2c8b78b4a -r 18a946ec74c8 render_sdl.c --- a/render_sdl.c Tue Oct 09 09:29:28 2018 -0700 +++ b/render_sdl.c Wed Oct 24 21:10:12 2018 -0700 @@ -1645,9 +1645,48 @@ } } +int render_lookup_button(char *name) +{ + static tern_node *button_lookup; + if (!button_lookup) { + for (int i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) + { + button_lookup = tern_insert_int(button_lookup, SDL_GameControllerGetStringForButton(i), i); + } + //alternative Playstation-style names + button_lookup = tern_insert_int(button_lookup, "cross", SDL_CONTROLLER_BUTTON_A); + button_lookup = tern_insert_int(button_lookup, "circle", SDL_CONTROLLER_BUTTON_B); + button_lookup = tern_insert_int(button_lookup, "square", SDL_CONTROLLER_BUTTON_X); + button_lookup = tern_insert_int(button_lookup, "triangle", SDL_CONTROLLER_BUTTON_Y); + button_lookup = tern_insert_int(button_lookup, "share", SDL_CONTROLLER_BUTTON_BACK); + button_lookup = tern_insert_int(button_lookup, "select", SDL_CONTROLLER_BUTTON_BACK); + button_lookup = tern_insert_int(button_lookup, "options", SDL_CONTROLLER_BUTTON_START); + button_lookup = tern_insert_int(button_lookup, "l1", SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + button_lookup = tern_insert_int(button_lookup, "r1", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + button_lookup = tern_insert_int(button_lookup, "l3", SDL_CONTROLLER_BUTTON_LEFTSTICK); + button_lookup = tern_insert_int(button_lookup, "r3", SDL_CONTROLLER_BUTTON_RIGHTSTICK); + } + return (int)tern_find_int(button_lookup, name, SDL_CONTROLLER_BUTTON_INVALID); +} + +int render_lookup_axis(char *name) +{ + static tern_node *axis_lookup; + if (!axis_lookup) { + for (int i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) + { + axis_lookup = tern_insert_int(axis_lookup, SDL_GameControllerGetStringForAxis(i), i); + } + //alternative Playstation-style names + axis_lookup = tern_insert_int(axis_lookup, "l2", SDL_CONTROLLER_AXIS_TRIGGERLEFT); + axis_lookup = tern_insert_int(axis_lookup, "r2", SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + } + return (int)tern_find_int(axis_lookup, name, SDL_CONTROLLER_AXIS_INVALID); +} + int32_t render_translate_input_name(int32_t controller, char *name, uint8_t is_axis) { - static tern_node *button_lookup, *axis_lookup; + tern_node *button_lookup, *axis_lookup; if (controller > MAX_JOYSTICKS || !joysticks[controller]) { return RENDER_NOT_PLUGGED_IN; } @@ -1663,41 +1702,15 @@ SDL_GameControllerButtonBind cbind; if (is_axis) { - if (!axis_lookup) { - for (int i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) - { - axis_lookup = tern_insert_int(axis_lookup, SDL_GameControllerGetStringForAxis(i), i); - } - //alternative Playstation-style names - axis_lookup = tern_insert_int(axis_lookup, "l2", SDL_CONTROLLER_AXIS_TRIGGERLEFT); - axis_lookup = tern_insert_int(axis_lookup, "r2", SDL_CONTROLLER_AXIS_TRIGGERRIGHT); - } - intptr_t sdl_axis = tern_find_int(axis_lookup, name, SDL_CONTROLLER_AXIS_INVALID); + + int sdl_axis = render_lookup_axis(name); if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) { SDL_GameControllerClose(control); return RENDER_INVALID_NAME; } cbind = SDL_GameControllerGetBindForAxis(control, sdl_axis); } else { - if (!button_lookup) { - for (int i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) - { - button_lookup = tern_insert_int(button_lookup, SDL_GameControllerGetStringForButton(i), i); - } - //alternative Playstation-style names - button_lookup = tern_insert_int(button_lookup, "cross", SDL_CONTROLLER_BUTTON_A); - button_lookup = tern_insert_int(button_lookup, "circle", SDL_CONTROLLER_BUTTON_B); - button_lookup = tern_insert_int(button_lookup, "square", SDL_CONTROLLER_BUTTON_X); - button_lookup = tern_insert_int(button_lookup, "triangle", SDL_CONTROLLER_BUTTON_Y); - button_lookup = tern_insert_int(button_lookup, "share", SDL_CONTROLLER_BUTTON_BACK); - button_lookup = tern_insert_int(button_lookup, "select", SDL_CONTROLLER_BUTTON_BACK); - button_lookup = tern_insert_int(button_lookup, "options", SDL_CONTROLLER_BUTTON_START); - button_lookup = tern_insert_int(button_lookup, "l1", SDL_CONTROLLER_BUTTON_LEFTSHOULDER); - button_lookup = tern_insert_int(button_lookup, "r1", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); - button_lookup = tern_insert_int(button_lookup, "l3", SDL_CONTROLLER_BUTTON_LEFTSTICK); - button_lookup = tern_insert_int(button_lookup, "r3", SDL_CONTROLLER_BUTTON_RIGHTSTICK); - } - intptr_t sdl_button = tern_find_int(button_lookup, name, SDL_CONTROLLER_BUTTON_INVALID); + int sdl_button = render_lookup_button(name); if (sdl_button == SDL_CONTROLLER_BUTTON_INVALID) { SDL_GameControllerClose(control); return RENDER_INVALID_NAME; diff -r 4bb2c8b78b4a -r 18a946ec74c8 render_sdl.h --- a/render_sdl.h Tue Oct 09 09:29:28 2018 -0700 +++ b/render_sdl.h Wed Oct 24 21:10:12 2018 -0700 @@ -12,6 +12,7 @@ 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); - +int render_lookup_button(char *name); +int render_lookup_axis(char *name); #endif //RENDER_SDL_H_