Mercurial > repos > blastem
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; |