comparison nuklear_ui/blastem_nuklear.c @ 2053:3414a4423de1 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 15 Jan 2022 13:15:21 -0800
parents 380bc5d4a2cf
children 237068a25523
comparison
equal deleted inserted replaced
1692:5dacaef602a7 2053:3414a4423de1
1 #define NK_IMPLEMENTATION 1 #define NK_IMPLEMENTATION
2 #define NK_SDL_GLES2_IMPLEMENTATION 2 #define NK_SDL_GLES2_IMPLEMENTATION
3 #define NK_RAWFB_IMPLEMENTATION
4 #define RAWFB_RGBX_8888
3 5
4 #include <stdlib.h> 6 #include <stdlib.h>
5 #include <limits.h> 7 #include <limits.h>
8 #include <math.h>
6 #include "blastem_nuklear.h" 9 #include "blastem_nuklear.h"
10 #include "nuklear_rawfb.h"
7 #include "font.h" 11 #include "font.h"
8 #include "../render.h" 12 #include "../render.h"
9 #include "../render_sdl.h" 13 #include "../render_sdl.h"
10 #include "../util.h" 14 #include "../util.h"
11 #include "../paths.h" 15 #include "../paths.h"
16 #include "../png.h" 20 #include "../png.h"
17 #include "../controller_info.h" 21 #include "../controller_info.h"
18 #include "../bindings.h" 22 #include "../bindings.h"
19 23
20 static struct nk_context *context; 24 static struct nk_context *context;
25 static struct rawfb_context *fb_context;
21 26
22 typedef struct 27 typedef struct
23 { 28 {
24 uint32_t *image_data; 29 uint32_t *image_data;
25 uint32_t width, height; 30 uint32_t width, height;
26 struct nk_image ui; 31 struct nk_image ui;
27 } ui_image; 32 } ui_image;
28 33
29 static ui_image **ui_images, *controller_360, *controller_ps4, *controller_ps4_6b; 34 static ui_image **ui_images, *controller_360, *controller_ps4,
35 *controller_ps4_6b, *controller_wiiu, *controller_gen_6b;
30 static uint32_t num_ui_images, ui_image_storage; 36 static uint32_t num_ui_images, ui_image_storage;
31 37
32 typedef void (*view_fun)(struct nk_context *); 38 typedef void (*view_fun)(struct nk_context *);
33 static view_fun current_view; 39 static view_fun current_view;
34 static view_fun *previous_views; 40 static view_fun *previous_views;
43 view_storage = view_storage ? 2*view_storage : 2; 49 view_storage = view_storage ? 2*view_storage : 2;
44 previous_views = realloc(previous_views, view_storage*sizeof(view_fun)); 50 previous_views = realloc(previous_views, view_storage*sizeof(view_fun));
45 } 51 }
46 previous_views[num_prev++] = current_view; 52 previous_views[num_prev++] = current_view;
47 current_view = new_view; 53 current_view = new_view;
54 context->input.selected_widget = 0;
48 } 55 }
49 56
50 static void pop_view() 57 static void pop_view()
51 { 58 {
52 if (num_prev) { 59 if (num_prev) {
53 current_view = previous_views[--num_prev]; 60 current_view = previous_views[--num_prev];
61 context->input.selected_widget = 0;
54 } 62 }
55 } 63 }
56 64
57 static void clear_view_stack() 65 static void clear_view_stack()
58 { 66 {
79 if (!entries) { 87 if (!entries) {
80 entries = get_dir_list(current_path, &num_entries); 88 entries = get_dir_list(current_path, &num_entries);
81 if (entries) { 89 if (entries) {
82 sort_dir_list(entries, num_entries); 90 sort_dir_list(entries, num_entries);
83 } 91 }
92 if (!num_entries) {
93 //get_dir_list can fail if the user doesn't have permission
94 //for the current folder, make sure they can still navigate up
95 free_dir_list(entries, num_entries);
96 entries = calloc(1, sizeof(dir_entry));
97 entries[0].name = strdup("..");
98 entries[0].is_dir = 1;
99 num_entries = 1;
100 }
84 } 101 }
85 if (!got_ext_list) { 102 if (!got_ext_list) {
86 ext_list = get_extension_list(config, &num_exts); 103 ext_list = get_extension_list(config, &num_exts);
87 got_ext_list = 1; 104 got_ext_list = 1;
88 } 105 }
89 uint32_t width = render_width(); 106 uint32_t width = render_width();
90 uint32_t height = render_height(); 107 uint32_t height = render_height();
91 if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) { 108 if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) {
92 nk_layout_row_static(context, height - context->style.font->height * 3, width - 60, 1); 109 nk_layout_row_static(context, height - context->style.font->height * 3, width - 60, 1);
93 int32_t old_selected = selected_entry; 110 int32_t old_selected = selected_entry;
94 if (nk_group_begin(context, "Select ROM", NK_WINDOW_BORDER | NK_WINDOW_TITLE)) { 111 char *title = alloc_concat("Select ROM: ", current_path);
112 if (nk_group_begin(context, title, NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
95 nk_layout_row_static(context, context->style.font->height - 2, width-100, 1); 113 nk_layout_row_static(context, context->style.font->height - 2, width-100, 1);
96 for (int32_t i = 0; i < num_entries; i++) 114 for (int32_t i = 0; i < num_entries; i++)
97 { 115 {
98 if (entries[i].name[0] == '.' && entries[i].name[1] != '.') { 116 if (entries[i].name[0] == '.' && entries[i].name[1] != '.') {
99 continue; 117 continue;
109 selected_entry = -1; 127 selected_entry = -1;
110 } 128 }
111 } 129 }
112 nk_group_end(context); 130 nk_group_end(context);
113 } 131 }
132 free(title);
114 nk_layout_row_static(context, context->style.font->height * 1.75, width > 600 ? 300 : width / 2, 2); 133 nk_layout_row_static(context, context->style.font->height * 1.75, width > 600 ? 300 : width / 2, 2);
115 if (nk_button_label(context, "Back")) { 134 if (nk_button_label(context, "Back")) {
116 pop_view(); 135 pop_view();
117 } 136 }
118 if (nk_button_label(context, "Open") || (old_selected >= 0 && selected_entry < 0)) { 137 if (nk_button_label(context, "Open") || (old_selected >= 0 && selected_entry < 0)) {
158 } 177 }
159 178
160 void view_about(struct nk_context *context) 179 void view_about(struct nk_context *context)
161 { 180 {
162 const char *lines[] = { 181 const char *lines[] = {
163 "BlastEm v0.6.1", 182 "BlastEm v0.6.3-pre",
164 "Copyright 2012-2017 Michael Pavone", 183 "Copyright 2012-2019 Michael Pavone",
165 "", 184 "",
166 "BlastEm is a high performance open source", 185 "BlastEm is a high performance open source",
167 "(GPLv3) Genesis/Megadrive emulator", 186 "(GPLv3) Genesis/Megadrive emulator",
168 }; 187 };
169 const uint32_t NUM_LINES = sizeof(lines)/sizeof(*lines); 188 const uint32_t NUM_LINES = sizeof(lines)/sizeof(*lines);
170 const char *thanks[] = { 189 const char *thanks[] = {
171 "Nemesis: Documentation and test ROMs", 190 "Nemesis: Documentation and test ROMs",
172 "Charles MacDonald: Documentation", 191 "Charles MacDonald: Documentation",
173 "Eke-Eke: Documentation", 192 "Eke-Eke: Documentation",
193 "Sauraen: YM2612/YM2203 Die Analysis",
194 "Alexey Khokholov: YM3438 Die Analysis",
174 "Bart Trzynadlowski: Documentation", 195 "Bart Trzynadlowski: Documentation",
175 "KanedaFR: Hosting the best Sega forum", 196 "KanedaFR: Hosting the best Sega forum",
176 "Titan: Awesome demos and documentation", 197 "Titan: Awesome demos and documentation",
177 "flamewing: BCD info and test ROM", 198 "flamewing: BCD info and test ROM",
178 "r57shell: Opcode size test ROM", 199 "r57shell: Opcode size test ROM",
291 push_view(items[i].next_view); 312 push_view(items[i].next_view);
292 if (current_view == view_save_state || current_view == view_load_state) { 313 if (current_view == view_save_state || current_view == view_load_state) {
293 free_slot_info(slots); 314 free_slot_info(slots);
294 slots = NULL; 315 slots = NULL;
295 } else if (current_view == view_play) { 316 } else if (current_view == view_play) {
317 clear_view_stack();
296 set_content_binding_state(1); 318 set_content_binding_state(1);
297 } 319 }
298 } else { 320 } else {
299 handler(i); 321 handler(i);
300 } 322 }
312 *binding_lookup = tern_insert_ptr(*binding_lookup, val.ptrval, strdup(key)); 334 *binding_lookup = tern_insert_ptr(*binding_lookup, val.ptrval, strdup(key));
313 } 335 }
314 336
315 static int32_t keycode; 337 static int32_t keycode;
316 static const char *set_binding; 338 static const char *set_binding;
339 static uint8_t bind_click_release, click;
317 char *set_label; 340 char *set_label;
318 void binding_group(struct nk_context *context, char *name, const char **binds, const char **bind_names, uint32_t num_binds, tern_node *binding_lookup) 341 void binding_group(struct nk_context *context, char *name, const char **binds, const char **bind_names, uint32_t num_binds, tern_node *binding_lookup)
319 { 342 {
320 nk_layout_row_static(context, (context->style.font->height + 4)*num_binds+context->style.font->height+30, render_width() - 80, 1); 343 nk_layout_row_static(context, (context->style.font->height + 4)*num_binds+context->style.font->height+30, render_width() - 80, 1);
321 if (nk_group_begin(context, name, NK_WINDOW_TITLE)) { 344 if (nk_group_begin(context, name, NK_WINDOW_TITLE)) {
330 } 353 }
331 nk_label(context, label, NK_TEXT_LEFT); 354 nk_label(context, label, NK_TEXT_LEFT);
332 if (nk_button_label(context, tern_find_ptr_default(binding_lookup, binds[i], "Not Set"))) { 355 if (nk_button_label(context, tern_find_ptr_default(binding_lookup, binds[i], "Not Set"))) {
333 set_binding = binds[i]; 356 set_binding = binds[i];
334 set_label = strdup(label); 357 set_label = strdup(label);
358 bind_click_release = 0;
335 keycode = 0; 359 keycode = 0;
336 } 360 }
337 if (label_alloc) { 361 if (label_alloc) {
338 free(label_alloc); 362 free(label_alloc);
339 } 363 }
427 "gamepads.2.x", "gamepads.2.y", "gamepads.2.z", 451 "gamepads.2.x", "gamepads.2.y", "gamepads.2.z",
428 "gamepads.2.start", "gamepads.2.mode" 452 "gamepads.2.start", "gamepads.2.mode"
429 }; 453 };
430 const char *general_binds[] = { 454 const char *general_binds[] = {
431 "ui.exit", "ui.save_state", "ui.toggle_fullscreen", "ui.soft_reset", "ui.reload", 455 "ui.exit", "ui.save_state", "ui.toggle_fullscreen", "ui.soft_reset", "ui.reload",
432 "ui.screenshot", "ui.sms_pause", "ui.toggle_keyboard_cpatured", "ui.release_mouse" 456 "ui.screenshot", "ui.vgm_log", "ui.sms_pause", "ui.toggle_keyboard_cpatured", "ui.release_mouse"
433 }; 457 };
434 const char *general_names[] = { 458 const char *general_names[] = {
435 "Show Menu", "Quick Save", "Toggle Fullscreen", "Soft Reset", "Reload Media", 459 "Show Menu", "Quick Save", "Toggle Fullscreen", "Soft Reset", "Reload Media",
436 "Internal Screenshot", "SMS Pause", "Capture Keyboard", "Release Mouse" 460 "Internal Screenshot", "Toggle VGM Log", "SMS Pause", "Capture Keyboard", "Release Mouse"
437 }; 461 };
438 const char *speed_binds[] = { 462 const char *speed_binds[] = {
439 "ui.next_speed", "ui.prev_speed", 463 "ui.next_speed", "ui.prev_speed",
440 "ui.set_speed.0", "ui.set_speed.1", "ui.set_speed.2" ,"ui.set_speed.3", "ui.set_speed.4", 464 "ui.set_speed.0", "ui.set_speed.1", "ui.set_speed.2" ,"ui.set_speed.3", "ui.set_speed.4",
441 "ui.set_speed.5", "ui.set_speed.6", "ui.set_speed.7" ,"ui.set_speed.8", "ui.set_speed.9", 465 "ui.set_speed.5", "ui.set_speed.6", "ui.set_speed.7" ,"ui.set_speed.8", "ui.set_speed.9",
481 } 505 }
482 if (set_binding && nk_begin(context, "Set Binding", nk_rect(width/4, height/4, width/2/*width*3/4*/, height/2), NK_WINDOW_TITLE | NK_WINDOW_BORDER)) { 506 if (set_binding && nk_begin(context, "Set Binding", nk_rect(width/4, height/4, width/2/*width*3/4*/, height/2), NK_WINDOW_TITLE | NK_WINDOW_BORDER)) {
483 nk_layout_row_static(context, 30, width/2-30, 1); 507 nk_layout_row_static(context, 30, width/2-30, 1);
484 nk_label(context, "Press new key for", NK_TEXT_CENTERED); 508 nk_label(context, "Press new key for", NK_TEXT_CENTERED);
485 nk_label(context, set_label, NK_TEXT_CENTERED); 509 nk_label(context, set_label, NK_TEXT_CENTERED);
486 if (nk_button_label(context, "Cancel")) { 510 if (nk_button_label(context, "Cancel") && bind_click_release) {
487 free(set_label); 511 free(set_label);
488 set_binding = set_label = NULL; 512 set_binding = set_label = NULL;
489 } else if (keycode) { 513 } else if (keycode) {
490 char *name = get_key_name(keycode); 514 char *name = get_key_name(keycode);
491 if (name) { 515 if (name) {
515 tern_free(binding_lookup); 539 tern_free(binding_lookup);
516 binding_lookup = NULL; 540 binding_lookup = NULL;
517 } 541 }
518 free(set_label); 542 free(set_label);
519 set_binding = set_label = NULL; 543 set_binding = set_label = NULL;
544 } else if (!click) {
545 bind_click_release = 1;
520 } 546 }
521 nk_end(context); 547 nk_end(context);
522 } 548 }
523 } 549 }
524 550
576 conf_names = tern_insert_ptr(conf_names, "ui.release_mouse", "Release Mouse"); 602 conf_names = tern_insert_ptr(conf_names, "ui.release_mouse", "Release Mouse");
577 conf_names = tern_insert_ptr(conf_names, "ui.vdp_debug_mode", "VDP Debug Mode"); 603 conf_names = tern_insert_ptr(conf_names, "ui.vdp_debug_mode", "VDP Debug Mode");
578 conf_names = tern_insert_ptr(conf_names, "ui.vdp_debug_pal", "VDP Debug Palette"); 604 conf_names = tern_insert_ptr(conf_names, "ui.vdp_debug_pal", "VDP Debug Palette");
579 conf_names = tern_insert_ptr(conf_names, "ui.enter_debugger", "Enter CPU Debugger"); 605 conf_names = tern_insert_ptr(conf_names, "ui.enter_debugger", "Enter CPU Debugger");
580 conf_names = tern_insert_ptr(conf_names, "ui.screenshot", "Take Screenshot"); 606 conf_names = tern_insert_ptr(conf_names, "ui.screenshot", "Take Screenshot");
607 conf_names = tern_insert_ptr(conf_names, "ui.vgm_log", "Toggle VGM Log");
581 conf_names = tern_insert_ptr(conf_names, "ui.exit", "Show Menu"); 608 conf_names = tern_insert_ptr(conf_names, "ui.exit", "Show Menu");
582 conf_names = tern_insert_ptr(conf_names, "ui.save_state", "Quick Save"); 609 conf_names = tern_insert_ptr(conf_names, "ui.save_state", "Quick Save");
583 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.0", "Set Speed 0"); 610 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.0", "Set Speed 0");
584 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.1", "Set Speed 1"); 611 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.1", "Set Speed 1");
585 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.2", "Set Speed 2"); 612 conf_names = tern_insert_ptr(conf_names, "ui.set_speed.2", "Set Speed 2");
960 free((char *)options[SIMILAR_CONTROLLERS].title); 987 free((char *)options[SIMILAR_CONTROLLERS].title);
961 } 988 }
962 989
963 static ui_image *select_best_image(controller_info *info) 990 static ui_image *select_best_image(controller_info *info)
964 { 991 {
965 if (info->variant != VARIANT_NORMAL) { 992 if (info->variant != VARIANT_NORMAL || info->type == TYPE_SEGA) {
966 return controller_ps4_6b; 993 if (info->type == TYPE_PSX) {
994 return controller_ps4_6b;
995 } else {
996 return controller_gen_6b;
997 }
967 } else if (info->type == TYPE_PSX) { 998 } else if (info->type == TYPE_PSX) {
968 return controller_ps4; 999 return controller_ps4;
1000 } else if (info->type == TYPE_NINTENDO) {
1001 return controller_wiiu;
969 } else { 1002 } else {
970 return controller_360; 1003 return controller_360;
971 } 1004 }
972 } 1005 }
973 1006
1052 SDL_CONTROLLER_BUTTON_Y, 1085 SDL_CONTROLLER_BUTTON_Y,
1053 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_RIGHTSHOULDER : SDL_CONTROLLER_BUTTON_LEFTSHOULDER, 1086 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_RIGHTSHOULDER : SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
1054 }); 1087 });
1055 } 1088 }
1056 1089
1057 binding_box(context, bindings, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 1090 if (selected_controller_info.variant == VARIANT_NORMAL) {
1058 selected_controller_info.variant == VARIANT_6B_BUMPERS ? 1 : 2, 1091 binding_box(context, bindings, "Right Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
1059 (int[]){ 1092 SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
1060 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_LEFTSHOULDER : SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 1093 AXIS | SDL_CONTROLLER_AXIS_TRIGGERRIGHT
1061 AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT 1094 });
1062 }); 1095 } else {
1096 binding_box(context, bindings, "Right Shoulder", bind_box_left, font->height/2, bind_box_width,
1097 selected_controller_info.variant == VARIANT_6B_BUMPERS ? 1 : 2,
1098 (int[]){
1099 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_LEFTSHOULDER : AXIS | SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
1100 AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT
1101 });
1102 }
1063 1103
1064 binding_box(context, bindings, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){ 1104 binding_box(context, bindings, "Misc Buttons", (render_width() - bind_box_width) / 2, font->height/2, bind_box_width, 3, (int[]){
1065 SDL_CONTROLLER_BUTTON_BACK, 1105 SDL_CONTROLLER_BUTTON_BACK,
1066 SDL_CONTROLLER_BUTTON_GUIDE, 1106 SDL_CONTROLLER_BUTTON_GUIDE,
1067 SDL_CONTROLLER_BUTTON_START 1107 SDL_CONTROLLER_BUTTON_START
1094 } else { 1134 } else {
1095 dpad_left = bind_box_left; 1135 dpad_left = bind_box_left;
1096 dpad_top = img_top; 1136 dpad_top = img_top;
1097 } 1137 }
1098 1138
1099 binding_box(context, bindings, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 1139 if (selected_controller_info.variant == VARIANT_NORMAL) {
1100 selected_controller_info.variant == VARIANT_6B_BUMPERS ? 1 : 2, 1140 binding_box(context, bindings, "Left Shoulder", bind_box_left, font->height/2, bind_box_width, 2, (int[]){
1101 (int[]){ 1141 SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
1102 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_LEFTSTICK : SDL_CONTROLLER_BUTTON_LEFTSHOULDER, 1142 AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT
1103 SDL_CONTROLLER_BUTTON_RIGHTSTICK 1143 });
1104 }); 1144 } else {
1145 binding_box(context, bindings, "Left Shoulder", bind_box_left, font->height/2, bind_box_width,
1146 selected_controller_info.variant == VARIANT_6B_BUMPERS ? 1 : 2,
1147 (int[]){
1148 selected_controller_info.variant == VARIANT_6B_RIGHT ? SDL_CONTROLLER_BUTTON_LEFTSTICK : AXIS | SDL_CONTROLLER_AXIS_TRIGGERLEFT,
1149 SDL_CONTROLLER_BUTTON_RIGHTSTICK
1150 });
1151 }
1105 1152
1106 binding_box(context, bindings, "D-pad", dpad_left, dpad_top, bind_box_width, 4, (int[]){ 1153 binding_box(context, bindings, "D-pad", dpad_left, dpad_top, bind_box_width, 4, (int[]){
1107 SDL_CONTROLLER_BUTTON_DPAD_UP, 1154 SDL_CONTROLLER_BUTTON_DPAD_UP,
1108 SDL_CONTROLLER_BUTTON_DPAD_DOWN, 1155 SDL_CONTROLLER_BUTTON_DPAD_DOWN,
1109 SDL_CONTROLLER_BUTTON_DPAD_LEFT, 1156 SDL_CONTROLLER_BUTTON_DPAD_LEFT,
1112 1159
1113 nk_layout_space_end(context); 1160 nk_layout_space_end(context);
1114 1161
1115 def_font->handle.height = orig_height; 1162 def_font->handle.height = orig_height;
1116 nk_layout_row_static(context, orig_height + 4, (render_width() - 2*orig_height) / 4, 1); 1163 nk_layout_row_static(context, orig_height + 4, (render_width() - 2*orig_height) / 4, 1);
1117 if (nk_button_label(context, "Back")) { 1164 if (nk_button_label(context, controller_binding_changed ? "Save" : "Back")) {
1118 pop_view(); 1165 pop_view();
1119 if (controller_binding_changed) { 1166 if (controller_binding_changed) {
1120 push_view(view_select_binding_dest); 1167 push_view(view_select_binding_dest);
1121 } 1168 }
1122 } 1169 }
1126 1173
1127 static int current_button; 1174 static int current_button;
1128 static int current_axis; 1175 static int current_axis;
1129 static int button_pressed, last_button; 1176 static int button_pressed, last_button;
1130 static int hat_moved, hat_value, last_hat, last_hat_value; 1177 static int hat_moved, hat_value, last_hat, last_hat_value;
1131 static int axis_moved, axis_value, last_axis; 1178 static int axis_moved, axis_value, last_axis, last_axis_value;
1132 static char *mapping_string; 1179 static char *mapping_string;
1133 static size_t mapping_pos; 1180 static size_t mapping_pos;
1134 1181
1135 static void start_mapping(void) 1182 static void start_mapping(void)
1136 { 1183 {
1145 memcpy(mapping_string + mapping_pos, name, namesz); 1192 memcpy(mapping_string + mapping_pos, name, namesz);
1146 mapping_pos += namesz; 1193 mapping_pos += namesz;
1147 mapping_string[mapping_pos++] = ':'; 1194 mapping_string[mapping_pos++] = ':';
1148 } 1195 }
1149 1196
1197 static uint8_t initial_controller_config;
1150 #define QUIET_FRAMES 9 1198 #define QUIET_FRAMES 9
1151 static void view_controller_mappings(struct nk_context *context) 1199 static void view_controller_mappings(struct nk_context *context)
1152 { 1200 {
1153 char buffer[512]; 1201 char buffer[512];
1154 static int quiet, button_a = -1, button_a_axis = -1; 1202 static int quiet, button_a = -1, button_a_axis = -1;
1204 mapping_string[mapping_pos++] = '0' + hat_value; 1252 mapping_string[mapping_pos++] = '0' + hat_value;
1205 added_mapping = 1; 1253 added_mapping = 1;
1206 1254
1207 last_hat = hat_moved; 1255 last_hat = hat_moved;
1208 last_hat_value = hat_value; 1256 last_hat_value = hat_value;
1209 } else if (axis_moved >= 0 && abs(axis_value) > 1000 && axis_moved != last_axis) { 1257 } else if (axis_moved >= 0 && abs(axis_value) > 1000 && (
1258 axis_moved != last_axis || (
1259 axis_value/abs(axis_value) != last_axis_value/abs(axis_value) && current_button >= SDL_CONTROLLER_BUTTON_DPAD_UP
1260 )
1261 )) {
1210 if (current_button <= SDL_CONTROLLER_BUTTON_B || axis_moved != button_a_axis) { 1262 if (current_button <= SDL_CONTROLLER_BUTTON_B || axis_moved != button_a_axis) {
1211 start_mapping(); 1263 start_mapping();
1264 if (current_button >= SDL_CONTROLLER_BUTTON_DPAD_UP) {
1265 mapping_string[mapping_pos++] = axis_value >= 0 ? '+' : '-';
1266 }
1212 mapping_string[mapping_pos++] = 'a'; 1267 mapping_string[mapping_pos++] = 'a';
1213 if (axis_moved > 9) { 1268 if (axis_moved > 9) {
1214 mapping_string[mapping_pos++] = '0' + axis_moved / 10; 1269 mapping_string[mapping_pos++] = '0' + axis_moved / 10;
1215 } 1270 }
1216 mapping_string[mapping_pos++] = '0' + axis_moved % 10; 1271 mapping_string[mapping_pos++] = '0' + axis_moved % 10;
1217 last_axis = axis_moved; 1272 last_axis = axis_moved;
1273 last_axis_value = axis_value;
1218 } 1274 }
1219 added_mapping = 1; 1275 added_mapping = 1;
1220 } 1276 }
1221 } 1277 }
1222 1278
1223 if (added_mapping) { 1279 while (added_mapping) {
1224 quiet = QUIET_FRAMES; 1280 quiet = QUIET_FRAMES;
1225 if (current_button < SDL_CONTROLLER_BUTTON_MAX) { 1281 if (current_button < SDL_CONTROLLER_BUTTON_MAX) {
1226 current_button++; 1282 current_button++;
1227 if (current_button == SDL_CONTROLLER_BUTTON_MAX) { 1283 if (current_button == SDL_CONTROLLER_BUTTON_MAX) {
1228 current_axis = 0; 1284 current_axis = 0;
1285 if (get_axis_label(&selected_controller_info, current_axis)) {
1286 added_mapping = 0;
1287 }
1288 } else if (get_button_label(&selected_controller_info, current_button)) {
1289 added_mapping = 0;
1229 } 1290 }
1230 } else { 1291 } else {
1231 current_axis++; 1292 current_axis++;
1232 if (current_axis == SDL_CONTROLLER_AXIS_MAX) { 1293 if (current_axis == SDL_CONTROLLER_AXIS_MAX) {
1233 button_a = -1; 1294 button_a = -1;
1234 button_a_axis = -1; 1295 button_a_axis = -1;
1235 mapping_string[mapping_pos] = 0; 1296 mapping_string[mapping_pos] = 0;
1236 save_controller_mapping(selected_controller, mapping_string); 1297 save_controller_mapping(selected_controller, mapping_string);
1237 free(mapping_string); 1298 free(mapping_string);
1238 pop_view(); 1299 pop_view();
1239 push_view(view_controller_bindings); 1300 if (initial_controller_config) {
1240 controller_binding_changed = 0; 1301 push_view(view_controller_bindings);
1302 controller_binding_changed = 0;
1303 }
1304 added_mapping = 0;
1305 } else if (get_axis_label(&selected_controller_info, current_axis)) {
1306 added_mapping = 0;
1241 } 1307 }
1242 } 1308 }
1243 } 1309 }
1244 button_pressed = -1; 1310 button_pressed = -1;
1245 hat_moved = -1; 1311 hat_moved = -1;
1246 axis_moved = -1; 1312 axis_moved = -1;
1247 nk_end(context); 1313 nk_end(context);
1248 } 1314 }
1315 }
1316
1317 static void show_mapping_view(void)
1318 {
1319 current_button = SDL_CONTROLLER_BUTTON_A;
1320 button_pressed = -1;
1321 last_button = -1;
1322 last_hat = -1;
1323 axis_moved = -1;
1324 last_axis = -1;
1325 last_axis_value = 0;
1326 SDL_Joystick *joy = render_get_joystick(selected_controller);
1327 const char *name = SDL_JoystickName(joy);
1328 size_t namesz = strlen(name);
1329 mapping_string = malloc(512 + namesz);
1330 for (mapping_pos = 0; mapping_pos < namesz; mapping_pos++)
1331 {
1332 char c = name[mapping_pos];
1333 if (c == ',' || c == '\n' || c == '\r') {
1334 c = ' ';
1335 }
1336 mapping_string[mapping_pos] = c;
1337 }
1338
1339 push_view(view_controller_mappings);
1249 } 1340 }
1250 1341
1251 static void view_controller_variant(struct nk_context *context) 1342 static void view_controller_variant(struct nk_context *context)
1252 { 1343 {
1253 uint8_t selected = 0; 1344 uint8_t selected = 0;
1255 nk_layout_row_static(context, context->style.font->height*1.25, render_width() - context->style.font->height * 2, 1); 1346 nk_layout_row_static(context, context->style.font->height*1.25, render_width() - context->style.font->height * 2, 1);
1256 nk_label(context, "", NK_TEXT_CENTERED); 1347 nk_label(context, "", NK_TEXT_CENTERED);
1257 nk_label(context, "Select the layout that", NK_TEXT_CENTERED); 1348 nk_label(context, "Select the layout that", NK_TEXT_CENTERED);
1258 nk_label(context, "best matches your controller", NK_TEXT_CENTERED); 1349 nk_label(context, "best matches your controller", NK_TEXT_CENTERED);
1259 nk_label(context, "", NK_TEXT_CENTERED); 1350 nk_label(context, "", NK_TEXT_CENTERED);
1260 if (nk_button_label(context, "4 face buttons")) { 1351 if (selected_controller_info.subtype == SUBTYPE_GENESIS) {
1261 selected_controller_info.variant = VARIANT_NORMAL; 1352 if (nk_button_label(context, "3 button")) {
1262 selected = 1; 1353 selected_controller_info.variant = VARIANT_3BUTTON;
1263 } 1354 selected = 1;
1264 char buffer[512]; 1355 }
1265 snprintf(buffer, sizeof(buffer), "6 face buttons including %s and %s", 1356 if (nk_button_label(context, "Standard 6 button")) {
1266 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), 1357 selected_controller_info.variant = VARIANT_6B_BUMPERS;
1267 get_axis_label(&selected_controller_info, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) 1358 selected = 1;
1268 ); 1359 }
1269 if (nk_button_label(context, buffer)) { 1360 if (nk_button_label(context, "6 button with 2 shoulder buttons")) {
1270 selected_controller_info.variant = VARIANT_6B_RIGHT; 1361 selected_controller_info.variant = VARIANT_8BUTTON;
1271 selected = 1; 1362 selected = 1;
1272 } 1363 }
1273 snprintf(buffer, sizeof(buffer), "6 face buttons including %s and %s", 1364 } else {
1274 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_LEFTSHOULDER), 1365 if (nk_button_label(context, "4 face buttons")) {
1275 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) 1366 selected_controller_info.variant = VARIANT_NORMAL;
1276 ); 1367 selected = 1;
1277 if (nk_button_label(context, buffer)) { 1368 }
1278 selected_controller_info.variant = VARIANT_6B_BUMPERS; 1369 char buffer[512];
1279 selected = 1; 1370 snprintf(buffer, sizeof(buffer), "6 face buttons including %s and %s",
1371 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER),
1372 get_axis_label(&selected_controller_info, SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
1373 );
1374 if (nk_button_label(context, buffer)) {
1375 selected_controller_info.variant = VARIANT_6B_RIGHT;
1376 selected = 1;
1377 }
1378 snprintf(buffer, sizeof(buffer), "6 face buttons including %s and %s",
1379 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_LEFTSHOULDER),
1380 get_button_label(&selected_controller_info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
1381 );
1382 if (nk_button_label(context, buffer)) {
1383 selected_controller_info.variant = VARIANT_6B_BUMPERS;
1384 selected = 1;
1385 }
1280 } 1386 }
1281 nk_end(context); 1387 nk_end(context);
1282 } 1388 }
1283 if (selected) { 1389 if (selected) {
1284 save_controller_info(selected_controller, &selected_controller_info); 1390 save_controller_info(selected_controller, &selected_controller_info);
1285 pop_view(); 1391 pop_view();
1286 SDL_GameController *controller = render_get_controller(selected_controller); 1392 if (initial_controller_config) {
1287 if (controller) { 1393 SDL_GameController *controller = render_get_controller(selected_controller);
1288 push_view(view_controller_bindings); 1394 if (controller) {
1289 controller_binding_changed = 0; 1395 push_view(view_controller_bindings);
1290 SDL_GameControllerClose(controller); 1396 controller_binding_changed = 0;
1291 } else { 1397 SDL_GameControllerClose(controller);
1292 current_button = SDL_CONTROLLER_BUTTON_A; 1398 } else {
1293 button_pressed = -1; 1399 show_mapping_view();
1294 last_button = -1; 1400 }
1295 last_hat = -1;
1296 axis_moved = -1;
1297 last_axis = -1;
1298 SDL_Joystick *joy = render_get_joystick(selected_controller);
1299 const char *name = SDL_JoystickName(joy);
1300 size_t namesz = strlen(name);
1301 mapping_string = malloc(512 + namesz);
1302 for (mapping_pos = 0; mapping_pos < namesz; mapping_pos++)
1303 {
1304 char c = name[mapping_pos];
1305 if (c == ',' || c == '\n' || c == '\r') {
1306 c = ' ';
1307 }
1308 mapping_string[mapping_pos] = c;
1309 }
1310
1311 push_view(view_controller_mappings);
1312 } 1401 }
1313 } 1402 }
1314 } 1403 }
1315 1404
1316 static void controller_type_group(struct nk_context *context, char *name, int type_id, int first_subtype_id, const char **types, uint32_t num_types) 1405 static void controller_type_group(struct nk_context *context, char *name, int type_id, int first_subtype_id, const char **types, uint32_t num_types)
1322 { 1411 {
1323 if (nk_button_label(context, types[i])) { 1412 if (nk_button_label(context, types[i])) {
1324 selected_controller_info.type = type_id; 1413 selected_controller_info.type = type_id;
1325 selected_controller_info.subtype = first_subtype_id + i; 1414 selected_controller_info.subtype = first_subtype_id + i;
1326 pop_view(); 1415 pop_view();
1327 push_view(view_controller_variant); 1416 if (selected_controller_info.subtype == SUBTYPE_SATURN) {
1417 selected_controller_info.variant = VARIANT_6B_BUMPERS;
1418 save_controller_info(selected_controller, &selected_controller_info);
1419 if (initial_controller_config) {
1420 SDL_GameController *controller = render_get_controller(selected_controller);
1421 if (controller) {
1422 push_view(view_controller_bindings);
1423 controller_binding_changed = 0;
1424 SDL_GameControllerClose(controller);
1425 } else {
1426 show_mapping_view();
1427 }
1428 }
1429 } else {
1430 push_view(view_controller_variant);
1431 }
1328 } 1432 }
1329 } 1433 }
1330 nk_group_end(context); 1434 nk_group_end(context);
1331 } 1435 }
1332 } 1436 }
1351 } 1455 }
1352 1456
1353 void view_controllers(struct nk_context *context) 1457 void view_controllers(struct nk_context *context)
1354 { 1458 {
1355 if (nk_begin(context, "Controllers", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) { 1459 if (nk_begin(context, "Controllers", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
1356 int height = (render_width() - 2*context->style.font->height) / MAX_JOYSTICKS; 1460 int height = (render_height() - 2*context->style.font->height) / 5;
1461 int inner_height = height - context->style.window.spacing.y;
1462 const struct nk_user_font *font = context->style.font;
1463 int bindings_width = font->width(font->userdata, font->height, "Bindings", strlen("Bindings")) + context->style.button.padding.x * 2;
1464 int remap_width = font->width(font->userdata, font->height, "Remap", strlen("Remap")) + context->style.button.padding.x * 2;
1465 int change_type_width = font->width(font->userdata, font->height, "Change Type", strlen("Change Type")) + context->style.button.padding.x * 2;
1466 int total = bindings_width + remap_width + change_type_width;
1467 float bindings_ratio = (float)bindings_width / total;
1468 float remap_ratio = (float)remap_width / total;
1469 float change_type_ratio = (float)change_type_width / total;
1470
1471
1472 uint8_t found_controller = 0;
1357 for (int i = 0; i < MAX_JOYSTICKS; i++) 1473 for (int i = 0; i < MAX_JOYSTICKS; i++)
1358 { 1474 {
1359 SDL_Joystick *joy = render_get_joystick(i); 1475 SDL_Joystick *joy = render_get_joystick(i);
1360 if (joy) { 1476 if (joy) {
1477 found_controller = 1;
1361 controller_info info = get_controller_info(i); 1478 controller_info info = get_controller_info(i);
1362 ui_image *controller_image = select_best_image(&info); 1479 ui_image *controller_image = select_best_image(&info);
1363 int image_width = height * controller_image->width / controller_image->height; 1480 int image_width = inner_height * controller_image->width / controller_image->height;
1364 nk_layout_row_begin(context, NK_STATIC, height, 2); 1481 nk_layout_space_begin(context, NK_STATIC, height, INT_MAX);
1365 nk_layout_row_push(context, image_width); 1482 nk_layout_space_push(context, nk_rect(context->style.font->height / 2, 0, image_width, inner_height));
1366 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) { 1483 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) {
1367 nk_label(context, "?", NK_TEXT_CENTERED); 1484 nk_label(context, "?", NK_TEXT_CENTERED);
1368 } else { 1485 } else {
1369 nk_image(context, controller_image->ui); 1486 nk_image(context, controller_image->ui);
1370 } 1487 }
1371 nk_layout_row_push(context, render_width() - image_width - 2 * context->style.font->height); 1488 int button_start = image_width + context->style.font->height;
1372 if (nk_button_label(context, info.name)) { 1489 int button_area_width = render_width() - image_width - 2 * context->style.font->height;
1373 selected_controller = i; 1490
1374 selected_controller_info = info; 1491 nk_layout_space_push(context, nk_rect(button_start, 0, button_area_width, inner_height/2));
1375 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) { 1492 nk_label(context, info.name, NK_TEXT_CENTERED);
1493 const struct nk_user_font *font = context->style.font;
1494 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) {
1495 int button_width = font->width(font->userdata, font->height, "Configure", strlen("Configure"));
1496 nk_layout_space_push(context, nk_rect(button_start, height/2, button_width, inner_height/2));
1497 if (nk_button_label(context, "Configure")) {
1498 selected_controller = i;
1499 selected_controller_info = info;
1500 initial_controller_config = 1;
1376 push_view(view_controller_type); 1501 push_view(view_controller_type);
1377 } else { 1502 }
1503 } else {
1504 button_area_width -= 2 * context->style.window.spacing.x;
1505 bindings_width = bindings_ratio * button_area_width;
1506 nk_layout_space_push(context, nk_rect(button_start, height/2, bindings_width, inner_height/2));
1507 if (nk_button_label(context, "Bindings")) {
1508 selected_controller = i;
1509 selected_controller_info = info;
1378 push_view(view_controller_bindings); 1510 push_view(view_controller_bindings);
1379 controller_binding_changed = 0; 1511 controller_binding_changed = 0;
1380 } 1512 }
1381 1513 button_start += bindings_width + context->style.window.spacing.x;
1514 remap_width = remap_ratio * button_area_width;
1515 nk_layout_space_push(context, nk_rect(button_start, height/2, remap_width, inner_height/2));
1516 if (nk_button_label(context, "Remap")) {
1517 selected_controller = i;
1518 selected_controller_info = info;
1519 initial_controller_config = 0;
1520 show_mapping_view();
1521 }
1522 button_start += remap_width + context->style.window.spacing.x;
1523 change_type_width = change_type_ratio * button_area_width;
1524 nk_layout_space_push(context, nk_rect(button_start, height/2, change_type_width, inner_height/2));
1525 if (nk_button_label(context, "Change Type")) {
1526 selected_controller = i;
1527 selected_controller_info = info;
1528 initial_controller_config = 0;
1529 push_view(view_controller_type);
1530 }
1382 } 1531 }
1383 nk_layout_row_end(context); 1532 //nk_layout_row_end(context);
1384 } 1533 }
1534 }
1535 if (!found_controller) {
1536 nk_layout_row_static(context, context->style.font->height, render_width() - 2 * context->style.font->height, 1);
1537 nk_label(context, "No controllers detected", NK_TEXT_CENTERED);
1385 } 1538 }
1386 nk_layout_row_static(context, context->style.font->height, (render_width() - 2 * context->style.font->height) / 2, 2); 1539 nk_layout_row_static(context, context->style.font->height, (render_width() - 2 * context->style.font->height) / 2, 2);
1387 nk_label(context, "", NK_TEXT_LEFT); 1540 nk_label(context, "", NK_TEXT_LEFT);
1388 if (nk_button_label(context, "Back")) { 1541 if (nk_button_label(context, "Back")) {
1389 pop_view(); 1542 pop_view();
1419 buffer[len] = 0; 1572 buffer[len] = 0;
1420 if (strcmp(buffer, curstr)) { 1573 if (strcmp(buffer, curstr)) {
1421 config_dirty = 1; 1574 config_dirty = 1;
1422 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR); 1575 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
1423 } 1576 }
1577 }
1578
1579 void settings_string(struct nk_context *context, char *label, char *path, char *def)
1580 {
1581 nk_label(context, label, NK_TEXT_LEFT);
1582 char *curstr = tern_find_path_default(config, path, (tern_val){.ptrval = def}, TVAL_PTR).ptrval;
1583 uint32_t len = strlen(curstr);
1584 uint32_t buffer_len = len > 100 ? len + 1 : 101;
1585 char *buffer = malloc(buffer_len);
1586 memcpy(buffer, curstr, len);
1587 memset(buffer+len, 0, buffer_len-len);
1588 nk_edit_string(context, NK_EDIT_SIMPLE, buffer, &len, buffer_len-1, nk_filter_default);
1589 buffer[len] = 0;
1590 if (strcmp(buffer, curstr)) {
1591 config_dirty = 1;
1592 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
1593 }
1594 free(buffer);
1424 } 1595 }
1425 1596
1426 void settings_int_property(struct nk_context *context, char *label, char *name, char *path, int def, int min, int max) 1597 void settings_int_property(struct nk_context *context, char *label, char *name, char *path, int def, int min, int max)
1427 { 1598 {
1428 char *curstr = tern_find_path(config, path, TVAL_PTR).ptrval; 1599 char *curstr = tern_find_path(config, path, TVAL_PTR).ptrval;
1436 config_dirty = 1; 1607 config_dirty = 1;
1437 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR); 1608 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
1438 } 1609 }
1439 } 1610 }
1440 1611
1612 void settings_float_property(struct nk_context *context, char *label, char *name, char *path, float def, float min, float max, float step)
1613 {
1614 char *curstr = tern_find_path(config, path, TVAL_PTR).ptrval;
1615 float curval = curstr ? atof(curstr) : def;
1616 nk_label(context, label, NK_TEXT_LEFT);
1617 float val = curval;
1618 nk_property_float(context, name, min, &val, max, step, step);
1619 if (val != curval) {
1620 char buffer[64];
1621 sprintf(buffer, "%f", val);
1622 config_dirty = 1;
1623 config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
1624 }
1625 }
1626
1441 typedef struct { 1627 typedef struct {
1442 char *fragment; 1628 char *fragment;
1443 char *vertex; 1629 char *vertex;
1444 } shader_prog; 1630 } shader_prog;
1445 1631
1464 } 1650 }
1465 } 1651 }
1466 if (!dupe) { 1652 if (!dupe) {
1467 if (num_progs == prog_storage) { 1653 if (num_progs == prog_storage) {
1468 prog_storage = prog_storage ? prog_storage*2 : 4; 1654 prog_storage = prog_storage ? prog_storage*2 : 4;
1469 progs = realloc(progs, sizeof(progs) * prog_storage); 1655 progs = realloc(progs, sizeof(*progs) * prog_storage);
1470 } 1656 }
1471 progs[num_progs].vertex = NULL; 1657 progs[num_progs].vertex = NULL;
1472 progs[num_progs++].fragment = strdup(entries[i].name); 1658 progs[num_progs++].fragment = strdup(entries[i].name);
1473 } 1659 }
1474 } 1660 }
1510 progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage); 1696 progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage);
1511 } else { 1697 } else {
1512 progs = NULL; 1698 progs = NULL;
1513 prog_storage = 0; 1699 prog_storage = 0;
1514 } 1700 }
1701 #ifdef DATA_PATH
1702 shader_dir = path_append(DATA_PATH, "shaders");
1703 #else
1515 shader_dir = path_append(get_exe_dir(), "shaders"); 1704 shader_dir = path_append(get_exe_dir(), "shaders");
1705 #endif
1516 entries = get_dir_list(shader_dir, &num_entries); 1706 entries = get_dir_list(shader_dir, &num_entries);
1707 free(shader_dir);
1517 progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage); 1708 progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage);
1518 *num_out = num_progs; 1709 *num_out = num_progs;
1519 return progs; 1710 return progs;
1520 } 1711 }
1521 1712
1647 "512", 1838 "512",
1648 "256", 1839 "256",
1649 "128", 1840 "128",
1650 "64" 1841 "64"
1651 }; 1842 };
1843 const char *dac[] = {
1844 "zero_offset",
1845 "linear"
1846 };
1847 const char *dac_desc[] = {
1848 "Zero Offset",
1849 "Linear"
1850 };
1652 const uint32_t num_rates = sizeof(rates)/sizeof(*rates); 1851 const uint32_t num_rates = sizeof(rates)/sizeof(*rates);
1653 const uint32_t num_sizes = sizeof(sizes)/sizeof(*sizes); 1852 const uint32_t num_sizes = sizeof(sizes)/sizeof(*sizes);
1853 const uint32_t num_dacs = sizeof(dac)/sizeof(*dac);
1654 static int32_t selected_rate = -1; 1854 static int32_t selected_rate = -1;
1655 static int32_t selected_size = -1; 1855 static int32_t selected_size = -1;
1656 if (selected_rate < 0 || selected_size < 0) { 1856 static int32_t selected_dac = -1;
1857 if (selected_rate < 0 || selected_size < 0 || selected_dac < 0) {
1657 selected_rate = find_match(rates, num_rates, "autio\0rate\0", "48000"); 1858 selected_rate = find_match(rates, num_rates, "autio\0rate\0", "48000");
1658 selected_size = find_match(sizes, num_sizes, "audio\0buffer\0", "512"); 1859 selected_size = find_match(sizes, num_sizes, "audio\0buffer\0", "512");
1860 selected_dac = find_match(dac, num_dacs, "audio\0fm_dac\0", "zero_offset");
1659 } 1861 }
1660 uint32_t width = render_width(); 1862 uint32_t width = render_width();
1661 uint32_t height = render_height(); 1863 uint32_t height = render_height();
1662 uint32_t desired_width = context->style.font->height * 10; 1864 uint32_t desired_width = context->style.font->height * 10;
1663 if (desired_width > width) { 1865 if (desired_width > width) {
1666 if (nk_begin(context, "Audio Settings", nk_rect(0, 0, width, height), 0)) { 1868 if (nk_begin(context, "Audio Settings", nk_rect(0, 0, width, height), 0)) {
1667 nk_layout_row_static(context, context->style.font->height , desired_width, 2); 1869 nk_layout_row_static(context, context->style.font->height , desired_width, 2);
1668 selected_rate = settings_dropdown(context, "Rate in Hz", rates, num_rates, selected_rate, "audio\0rate\0"); 1870 selected_rate = settings_dropdown(context, "Rate in Hz", rates, num_rates, selected_rate, "audio\0rate\0");
1669 selected_size = settings_dropdown(context, "Buffer Samples", sizes, num_sizes, selected_size, "audio\0buffer\0"); 1871 selected_size = settings_dropdown(context, "Buffer Samples", sizes, num_sizes, selected_size, "audio\0buffer\0");
1670 settings_int_input(context, "Lowpass Cutoff Hz", "audio\0lowpass_cutoff\0", "3390"); 1872 settings_int_input(context, "Lowpass Cutoff Hz", "audio\0lowpass_cutoff\0", "3390");
1873 settings_float_property(context, "Gain (dB)", "Overall", "audio\0gain\0", 0, -30.0f, 30.0f, 0.5f);
1874 settings_float_property(context, "", "FM", "audio\0fm_gain\0", 0, -30.0f, 30.0f, 0.5f);
1875 settings_float_property(context, "", "PSG", "audio\0psg_gain\0", 0, -30.0f, 30.0f, 0.5f);
1876 selected_dac = settings_dropdown_ex(context, "FM DAC", dac, dac_desc, num_dacs, selected_dac, "audio\0fm_dac\0");
1671 if (nk_button_label(context, "Back")) { 1877 if (nk_button_label(context, "Back")) {
1672 pop_view(); 1878 pop_view();
1673 } 1879 }
1674 nk_end(context); 1880 nk_end(context);
1675 } 1881 }
1676 } 1882 }
1883 typedef struct {
1884 const char **models;
1885 const char **names;
1886 uint32_t num_models;
1887 uint32_t storage;
1888 } model_foreach_state;
1889 void model_iter(char *key, tern_val val, uint8_t valtype, void *data)
1890 {
1891 if (valtype != TVAL_NODE) {
1892 return;
1893 }
1894 model_foreach_state *state = data;
1895 if (state->num_models == state->storage) {
1896 state->storage *= 2;
1897 state->models = realloc(state->models, state->storage * sizeof(char *));
1898 state->names = realloc(state->names, state->storage * sizeof(char *));
1899 }
1900 char *def = strdup(key);
1901 state->models[state->num_models] = def;
1902 state->names[state->num_models++] = tern_find_ptr_default(val.ptrval, "name", def);
1903 }
1904
1905 typedef struct {
1906 const char **models;
1907 const char **names;
1908 } models;
1909
1910 models get_models(uint32_t *num_out)
1911 {
1912 tern_node *systems = get_systems_config();
1913 model_foreach_state state = {
1914 .models = calloc(4, sizeof(char *)),
1915 .names = calloc(4, sizeof(char *)),
1916 .num_models = 0,
1917 .storage = 4
1918 };
1919 tern_foreach(systems, model_iter, &state);
1920 *num_out = state.num_models;
1921 return (models){
1922 .models = state.models,
1923 .names = state.names
1924 };
1925 }
1926
1677 void view_system_settings(struct nk_context *context) 1927 void view_system_settings(struct nk_context *context)
1678 { 1928 {
1679 const char *sync_opts[] = { 1929 const char *sync_opts[] = {
1680 "video", 1930 "video",
1681 "audio" 1931 "audio"
1694 const uint32_t num_regions = sizeof(regions)/sizeof(*regions); 1944 const uint32_t num_regions = sizeof(regions)/sizeof(*regions);
1695 static int32_t selected_region = -1; 1945 static int32_t selected_region = -1;
1696 if (selected_region < 0) { 1946 if (selected_region < 0) {
1697 selected_region = find_match(region_codes, num_regions, "system\0default_region\0", "U"); 1947 selected_region = find_match(region_codes, num_regions, "system\0default_region\0", "U");
1698 } 1948 }
1949 static const char **model_opts;
1950 static const char **model_names;
1951 static uint32_t num_models;
1952 if (!model_opts) {
1953 models m = get_models(&num_models);
1954 model_opts = m.models;
1955 model_names = m.names;
1956 }
1957 static int32_t selected_model = -1;
1958 if (selected_model < 0) {
1959 selected_model = find_match(model_opts, num_models, "system\0model\0", "md1va3");
1960 }
1961
1699 const char *formats[] = { 1962 const char *formats[] = {
1700 "native", 1963 "native",
1701 "gst" 1964 "gst"
1702 }; 1965 };
1703 const uint32_t num_formats = sizeof(formats)/sizeof(*formats); 1966 const uint32_t num_formats = sizeof(formats)/sizeof(*formats);
1704 int32_t selected_format = -1; 1967 static int32_t selected_format = -1;
1705 if (selected_format < 0) { 1968 if (selected_format < 0) {
1706 selected_format = find_match(formats, num_formats, "ui\0state_format\0", "native"); 1969 selected_format = find_match(formats, num_formats, "ui\0state_format\0", "native");
1707 } 1970 }
1708 const char *ram_inits[] = { 1971 const char *ram_inits[] = {
1709 "zero", 1972 "zero",
1713 static int32_t selected_init = -1; 1976 static int32_t selected_init = -1;
1714 if (selected_init < 0) { 1977 if (selected_init < 0) {
1715 selected_init = find_match(ram_inits, num_inits, "system\0ram_init\0", "zero"); 1978 selected_init = find_match(ram_inits, num_inits, "system\0ram_init\0", "zero");
1716 } 1979 }
1717 const char *io_opts_1[] = { 1980 const char *io_opts_1[] = {
1981 "none",
1718 "gamepad2.1", 1982 "gamepad2.1",
1719 "gamepad3.1", 1983 "gamepad3.1",
1720 "gamepad6.1", 1984 "gamepad6.1",
1721 "mouse.1", 1985 "mouse.1",
1722 "saturn keyboard", 1986 "saturn keyboard",
1723 "xband keyboard" 1987 "xband keyboard"
1724 }; 1988 };
1725 const char *io_opts_2[] = { 1989 const char *io_opts_2[] = {
1990 "none",
1726 "gamepad2.2", 1991 "gamepad2.2",
1727 "gamepad3.2", 1992 "gamepad3.2",
1728 "gamepad6.2", 1993 "gamepad6.2",
1729 "mouse.1", 1994 "mouse.1",
1730 "saturn keyboard", 1995 "saturn keyboard",
1741 uint32_t width = render_width(); 2006 uint32_t width = render_width();
1742 uint32_t height = render_height(); 2007 uint32_t height = render_height();
1743 uint32_t desired_width = context->style.font->height * 10; 2008 uint32_t desired_width = context->style.font->height * 10;
1744 if (nk_begin(context, "System Settings", nk_rect(0, 0, width, height), 0)) { 2009 if (nk_begin(context, "System Settings", nk_rect(0, 0, width, height), 0)) {
1745 nk_layout_row_static(context, context->style.font->height, desired_width, 2); 2010 nk_layout_row_static(context, context->style.font->height, desired_width, 2);
2011
2012 selected_model = settings_dropdown_ex(context, "Model", model_opts, model_names, num_models, selected_model, "system\0model\0");
2013 selected_io_1 = settings_dropdown_ex(context, "IO Port 1 Device", io_opts_1, device_type_names, num_io, selected_io_1, "io\0devices\0""1\0");
2014 selected_io_2 = settings_dropdown_ex(context, "IO Port 2 Device", io_opts_2, device_type_names, num_io, selected_io_2, "io\0devices\0""2\0");
2015 selected_region = settings_dropdown_ex(context, "Default Region", region_codes, regions, num_regions, selected_region, "system\0default_region\0");
1746 selected_sync = settings_dropdown(context, "Sync Source", sync_opts, num_sync_opts, selected_sync, "system\0sync_source\0"); 2016 selected_sync = settings_dropdown(context, "Sync Source", sync_opts, num_sync_opts, selected_sync, "system\0sync_source\0");
1747 settings_int_property(context, "68000 Clock Divider", "", "clocks\0m68k_divider\0", 7, 1, 53); 2017 settings_int_property(context, "68000 Clock Divider", "", "clocks\0m68k_divider\0", 7, 1, 53);
1748 settings_toggle(context, "Remember ROM Path", "ui\0remember_path\0", 1);
1749 selected_region = settings_dropdown_ex(context, "Default Region", region_codes, regions, num_regions, selected_region, "system\0default_region\0");
1750 selected_format = settings_dropdown(context, "Save State Format", formats, num_formats, selected_format, "ui\0state_format\0"); 2018 selected_format = settings_dropdown(context, "Save State Format", formats, num_formats, selected_format, "ui\0state_format\0");
1751 selected_init = settings_dropdown(context, "Initial RAM Value", ram_inits, num_inits, selected_init, "system\0ram_init\0"); 2019 selected_init = settings_dropdown(context, "Initial RAM Value", ram_inits, num_inits, selected_init, "system\0ram_init\0");
1752 selected_io_1 = settings_dropdown_ex(context, "IO Port 1 Device", io_opts_1, device_type_names, num_io, selected_io_1, "io\0devices\0""1\0"); 2020 settings_toggle(context, "Remember ROM Path", "ui\0remember_path\0", 1);
1753 selected_io_2 = settings_dropdown_ex(context, "IO Port 2 Device", io_opts_2, device_type_names, num_io, selected_io_2, "io\0devices\0""2\0"); 2021 settings_toggle(context, "Save config with EXE", "ui\0config_in_exe_dir\0", 0);
2022 settings_string(context, "Game Save Path", "ui\0save_path\0", "$USERDATA/blastem/$ROMNAME");
2023
1754 if (nk_button_label(context, "Back")) { 2024 if (nk_button_label(context, "Back")) {
2025 pop_view();
2026 }
2027 nk_end(context);
2028 }
2029 }
2030
2031 void view_confirm_reset(struct nk_context *context)
2032 {
2033 if (nk_begin(context, "Reset Confirm", nk_rect(0, 0, render_width(), render_height()), 0)) {
2034 uint32_t desired_width = context->style.font->height * 20;
2035 nk_layout_row_static(context, context->style.font->height, desired_width, 1);
2036 nk_label(context, "This will reset all settings and controller", NK_TEXT_LEFT);
2037 nk_label(context, "mappings back to the defaults.", NK_TEXT_LEFT);
2038 nk_label(context, "Are you sure you want to proceed?", NK_TEXT_LEFT);
2039 nk_layout_row_static(context, context->style.font->height * 1.5, desired_width / 2, 2);
2040 if (nk_button_label(context, "Maybe not")) {
2041 pop_view();
2042 }
2043 if (nk_button_label(context, "Yep, delete it all")) {
2044 delete_custom_config();
2045 config = load_config();
2046 delete_controller_info();
2047 config_dirty = 1;
1755 pop_view(); 2048 pop_view();
1756 } 2049 }
1757 nk_end(context); 2050 nk_end(context);
1758 } 2051 }
1759 } 2052 }
1771 {"Key Bindings", view_key_bindings}, 2064 {"Key Bindings", view_key_bindings},
1772 {"Controllers", view_controllers}, 2065 {"Controllers", view_controllers},
1773 {"Video", view_video_settings}, 2066 {"Video", view_video_settings},
1774 {"Audio", view_audio_settings}, 2067 {"Audio", view_audio_settings},
1775 {"System", view_system_settings}, 2068 {"System", view_system_settings},
2069 {"Reset to Defaults", view_confirm_reset},
1776 {"Back", view_back} 2070 {"Back", view_back}
1777 }; 2071 };
1778 2072
1779 if (nk_begin(context, "Settings Menu", nk_rect(0, 0, render_width(), render_height()), 0)) { 2073 if (nk_begin(context, "Settings Menu", nk_rect(0, 0, render_width(), render_height()), 0)) {
1780 menu(context, sizeof(items)/sizeof(*items), items, NULL); 2074 menu(context, sizeof(items)/sizeof(*items), items, NULL);
1823 void blastem_nuklear_render(void) 2117 void blastem_nuklear_render(void)
1824 { 2118 {
1825 if (current_view != view_play) { 2119 if (current_view != view_play) {
1826 nk_input_end(context); 2120 nk_input_end(context);
1827 current_view(context); 2121 current_view(context);
1828 nk_sdl_render(NK_ANTI_ALIASING_ON, 512 * 1024, 128 * 1024); 2122 if (fb_context) {
2123 fb_context->fb.pixels = render_get_framebuffer(FRAMEBUFFER_UI, &fb_context->fb.pitch);
2124 nk_rawfb_render(fb_context, nk_rgb(0,0,0), 0);
2125 render_framebuffer_updated(FRAMEBUFFER_UI, render_width());
2126 } else {
2127 #ifndef DISABLE_OPENGL
2128 nk_sdl_render(NK_ANTI_ALIASING_ON, 512 * 1024, 128 * 1024);
2129 #endif
2130 }
1829 nk_input_begin(context); 2131 nk_input_begin(context);
1830 } 2132 }
1831 } 2133 }
1832 2134
1833 void ui_idle_loop(void) 2135 void ui_idle_loop(void)
1834 { 2136 {
2137 render_enable_gamepad_events(1);
1835 const uint32_t MIN_UI_DELAY = 15; 2138 const uint32_t MIN_UI_DELAY = 15;
1836 static uint32_t last; 2139 static uint32_t last;
1837 while (current_view != view_play) 2140 while (current_view != view_play)
1838 { 2141 {
1839 uint32_t current = render_elapsed_ms(); 2142 uint32_t current = render_elapsed_ms();
1846 if (config_dirty) { 2149 if (config_dirty) {
1847 apply_updated_config(); 2150 apply_updated_config();
1848 persist_config(config); 2151 persist_config(config);
1849 config_dirty = 0; 2152 config_dirty = 0;
1850 } 2153 }
2154 render_enable_gamepad_events(0);
1851 } 2155 }
1852 static void handle_event(SDL_Event *event) 2156 static void handle_event(SDL_Event *event)
1853 { 2157 {
1854 if (event->type == SDL_KEYDOWN) { 2158 if (event->type == SDL_KEYDOWN) {
1855 keycode = event->key.keysym.sym; 2159 keycode = event->key.keysym.sym;
1864 else if (event->type == SDL_JOYAXISMOTION) { 2168 else if (event->type == SDL_JOYAXISMOTION) {
1865 if (event->jaxis.axis == axis_moved || abs(event->jaxis.value) > abs(axis_value) || abs(event->jaxis.value) > 1000) { 2169 if (event->jaxis.axis == axis_moved || abs(event->jaxis.value) > abs(axis_value) || abs(event->jaxis.value) > 1000) {
1866 axis_moved = event->jaxis.axis; 2170 axis_moved = event->jaxis.axis;
1867 axis_value = event->jaxis.value; 2171 axis_value = event->jaxis.value;
1868 } 2172 }
2173 } else if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == 0) {
2174 click = 1;
2175 } else if (event->type == SDL_MOUSEBUTTONUP && event->button.button == 0) {
2176 click = 0;
1869 } 2177 }
1870 nk_sdl_handle_event(event); 2178 nk_sdl_handle_event(event);
1871 } 2179 }
1872 2180
1873 static void context_destroyed(void) 2181 static void context_destroyed(void)
1874 { 2182 {
1875 nk_sdl_shutdown(); 2183 if (context)
1876 } 2184 {
1877 2185 nk_sdl_shutdown();
2186 context = NULL;
2187 }
2188 }
2189
2190 static void fb_resize(void)
2191 {
2192 nk_rawfb_resize_fb(fb_context, NULL, render_width(), render_height(), 0);
2193 }
2194
2195 #ifndef DISABLE_OPENGL
1878 static struct nk_image load_image_texture(uint32_t *buf, uint32_t width, uint32_t height) 2196 static struct nk_image load_image_texture(uint32_t *buf, uint32_t width, uint32_t height)
1879 { 2197 {
1880 GLuint tex; 2198 GLuint tex;
1881 glGenTextures(1, &tex); 2199 glGenTextures(1, &tex);
1882 glBindTexture(GL_TEXTURE_2D, tex); 2200 glBindTexture(GL_TEXTURE_2D, tex);
1889 #else 2207 #else
1890 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buf); 2208 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buf);
1891 #endif 2209 #endif
1892 return nk_image_id((int)tex); 2210 return nk_image_id((int)tex);
1893 } 2211 }
2212 #endif
2213
2214 static struct nk_image load_image_rawfb(uint32_t *buf, uint32_t width, uint32_t height)
2215 {
2216 struct rawfb_image *fbimg = calloc(1, sizeof(struct rawfb_image));
2217 fbimg->pixels = buf;
2218 fbimg->pitch = width * sizeof(uint32_t);
2219 fbimg->w = width;
2220 fbimg->h = height;
2221 fbimg->format = NK_FONT_ATLAS_RGBA32;
2222 return nk_image_ptr(fbimg);
2223 }
1894 2224
1895 static void texture_init(void) 2225 static void texture_init(void)
1896 { 2226 {
1897 struct nk_font_atlas *atlas; 2227 struct nk_font_atlas *atlas;
1898 nk_sdl_font_stash_begin(&atlas); 2228 if (fb_context) {
2229 nk_rawfb_font_stash_begin(fb_context, &atlas);
2230 } else {
2231 #ifndef DISABLE_OPENGL
2232 nk_sdl_font_stash_begin(&atlas);
2233 #endif
2234 }
1899 uint32_t font_size; 2235 uint32_t font_size;
1900 uint8_t *font = default_font(&font_size); 2236 uint8_t *font = default_font(&font_size);
1901 if (!font) { 2237 if (!font) {
1902 fatal_error("Failed to find default font path\n"); 2238 fatal_error("Failed to find default font path\n");
1903 } 2239 }
1904 def_font = nk_font_atlas_add_from_memory(atlas, font, font_size, render_height() / 16, NULL); 2240 def_font = nk_font_atlas_add_from_memory(atlas, font, font_size, render_height() / 16, NULL);
1905 free(font); 2241 free(font);
1906 nk_sdl_font_stash_end(); 2242 if (fb_context) {
2243 nk_rawfb_font_stash_end(fb_context);
2244 } else {
2245 #ifndef DISABLE_OPENGL
2246 nk_sdl_font_stash_end();
2247 #endif
2248 }
1907 nk_style_set_font(context, &def_font->handle); 2249 nk_style_set_font(context, &def_font->handle);
1908 for (uint32_t i = 0; i < num_ui_images; i++) 2250 for (uint32_t i = 0; i < num_ui_images; i++)
1909 { 2251 {
1910 ui_images[i]->ui = load_image_texture(ui_images[i]->image_data, ui_images[i]->width, ui_images[i]->height); 2252 #ifndef DISABLE_OPENGL
1911 } 2253 if (fb_context) {
2254 #endif
2255 ui_images[i]->ui = load_image_rawfb(ui_images[i]->image_data, ui_images[i]->width, ui_images[i]->height);
2256 #ifndef DISABLE_OPENGL
2257 } else {
2258 ui_images[i]->ui = load_image_texture(ui_images[i]->image_data, ui_images[i]->width, ui_images[i]->height);
2259 }
2260 #endif
2261 }
2262 }
2263
2264 static void style_init(void)
2265 {
2266 context->style.checkbox.padding.x = render_height() / 120;
2267 context->style.checkbox.padding.y = render_height() / 120;
2268 context->style.checkbox.border = render_height() / 240;
2269 context->style.checkbox.cursor_normal.type = NK_STYLE_ITEM_COLOR;
2270 context->style.checkbox.cursor_normal.data.color = (struct nk_color){
2271 .r = 255, .g = 128, .b = 0, .a = 255
2272 };
2273 context->style.checkbox.cursor_hover = context->style.checkbox.cursor_normal;
2274 context->style.property.inc_button.text_hover = (struct nk_color){
2275 .r = 255, .g = 128, .b = 0, .a = 255
2276 };
2277 context->style.property.dec_button.text_hover = context->style.property.inc_button.text_hover;
2278 context->style.combo.button.text_hover = context->style.property.inc_button.text_hover;
1912 } 2279 }
1913 2280
1914 static void context_created(void) 2281 static void context_created(void)
1915 { 2282 {
1916 context = nk_sdl_init(render_get_window()); 2283 context = nk_sdl_init(render_get_window());
2284 nk_sdl_device_create();
2285 style_init();
1917 texture_init(); 2286 texture_init();
1918 } 2287 }
1919 2288
1920 void show_pause_menu(void) 2289 void show_pause_menu(void)
1921 { 2290 {
1922 set_content_binding_state(0); 2291 if (current_view == view_play) {
1923 context->style.window.background = nk_rgba(0, 0, 0, 128); 2292 set_content_binding_state(0);
1924 context->style.window.fixed_background = nk_style_item_color(nk_rgba(0, 0, 0, 128)); 2293 context->style.window.background = nk_rgba(0, 0, 0, 128);
1925 current_view = view_pause; 2294 context->style.window.fixed_background = nk_style_item_color(nk_rgba(0, 0, 0, 128));
1926 current_system->request_exit(current_system); 2295 current_view = view_pause;
2296 context->input.selected_widget = 0;
2297 system_request_exit(current_system, 1);
2298 } else if (current_system && !set_binding) {
2299 clear_view_stack();
2300 show_play_view();
2301 }
1927 } 2302 }
1928 2303
1929 void show_play_view(void) 2304 void show_play_view(void)
1930 { 2305 {
1931 set_content_binding_state(1); 2306 set_content_binding_state(1);
1932 current_view = view_play; 2307 current_view = view_play;
2308 context->input.selected_widget = 0;
1933 } 2309 }
1934 2310
1935 static uint8_t active; 2311 static uint8_t active;
1936 uint8_t is_nuklear_active(void) 2312 uint8_t is_nuklear_active(void)
1937 { 2313 {
1938 return active; 2314 return active;
1939 } 2315 }
1940 2316
1941 uint8_t is_nuklear_available(void) 2317 uint8_t is_nuklear_available(void)
1942 { 2318 {
1943 if (!render_has_gl()) { 2319 /*if (!render_has_gl()) {
1944 //currently no fallback if GL2 unavailable 2320 //currently no fallback if GL2 unavailable
1945 return 0; 2321 return 0;
1946 } 2322 }*/
1947 char *style = tern_find_path(config, "ui\0style\0", TVAL_PTR).ptrval; 2323 char *style = tern_find_path(config, "ui\0style\0", TVAL_PTR).ptrval;
1948 if (!style) { 2324 if (!style) {
1949 return 1; 2325 return 1;
1950 } 2326 }
1951 return strcmp(style, "rom") != 0; 2327 return strcmp(style, "rom") != 0;
1991 } 2367 }
1992 2368
1993 void blastem_nuklear_init(uint8_t file_loaded) 2369 void blastem_nuklear_init(uint8_t file_loaded)
1994 { 2370 {
1995 context = nk_sdl_init(render_get_window()); 2371 context = nk_sdl_init(render_get_window());
2372 #ifndef DISABLE_OPENGL
2373 if (render_has_gl()) {
2374 nk_sdl_device_create();
2375 } else {
2376 #endif
2377 fb_context = nk_rawfb_init(NULL, context, render_width(), render_height(), 0);
2378 render_set_ui_fb_resize_handler(fb_resize);
2379 #ifndef DISABLE_OPENGL
2380 }
2381 #endif
2382 style_init();
1996 2383
1997 controller_360 = load_ui_image("images/360.png"); 2384 controller_360 = load_ui_image("images/360.png");
1998 controller_ps4 = load_ui_image("images/ps4.png"); 2385 controller_ps4 = load_ui_image("images/ps4.png");
1999 controller_ps4_6b = load_ui_image("images/ps4_6b.png"); 2386 controller_ps4_6b = load_ui_image("images/ps4_6b.png");
2387 controller_wiiu = load_ui_image("images/wiiu.png");
2388 controller_gen_6b = load_ui_image("images/genesis_6b.png");
2000 2389
2001 texture_init(); 2390 texture_init();
2002 2391
2003 if (file_loaded) { 2392 if (file_loaded) {
2004 current_view = view_play; 2393 current_view = view_play;