NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

181 wiersze
5.0KB

  1. #include "menu.h"
  2. #include "nes.h"
  3. #include "action.h"
  4. #include "port.h"
  5. #include "draw.h"
  6. static nese_Action wait_for_input(void* plat, uint8_t* new_buttons) {
  7. nes_Input input = {0};
  8. nese_Action action = nese_update_input(plat, &input);
  9. uint8_t changed = 0;
  10. while (0 == changed && Action_OK == action) {
  11. uint8_t buttons = input.gamepads[0].buttons;
  12. // Sleep is implicit in nese_update_input
  13. action = nese_update_input(plat, &input);
  14. changed = (~buttons & input.gamepads[0].buttons);
  15. }
  16. if (NULL != new_buttons) *new_buttons = input.gamepads[0].buttons;
  17. return action;
  18. }
  19. static nese_Action wait_for_input_quiet(void* plat) {
  20. nes_Input input = {0};
  21. nese_Action action = nese_update_input(plat, &input);
  22. uint8_t buttons = input.gamepads[0].buttons;
  23. while (Action_Quit != action && buttons) {
  24. action = nese_update_input(plat, &input);
  25. buttons = input.gamepads[0].buttons;
  26. }
  27. return action;
  28. }
  29. nese_Action modal_popup(void* plat, const char* message, uint32_t color) {
  30. int w = 0;
  31. int h = 0;
  32. nese_text_size(plat, message, &w, &h);
  33. int x = ((int)nes_ppu_render_w - w) / 2;
  34. int y = ((int)nes_ppu_render_h - h) / 2;
  35. if (x < 5) x = 5;
  36. if (y < 5) y = 5;
  37. nese_Action action = 0;
  38. uint8_t buttons = 0;
  39. while (0 == action && 0 == buttons) {
  40. nese_draw_begin(plat);
  41. nese_draw_text(plat, message, x, y, color);
  42. nese_draw_finish(plat);
  43. action = wait_for_input(plat, &buttons);
  44. }
  45. return action;
  46. }
  47. static void fix_filename(char* dst, int n, const char* src) {
  48. for ( int i = 0;
  49. i < n && *src && '.' != *src;
  50. ++i, ++dst, ++src) {
  51. *dst = ('_' == *src ? ' ' : *src);
  52. }
  53. *dst = '\0';
  54. }
  55. static inline int n_visible(void) {
  56. return ((nes_ppu_render_h - 20) / 11);
  57. }
  58. static const uint32_t menu_colors[6] = {
  59. color_red, color_orange, color_yellow,
  60. color_green, color_blue, color_purple,
  61. };
  62. static void show_menu(void* plat, const Menu_State* menu,
  63. const File_List* files, int x) {
  64. nese_draw_begin(plat);
  65. int bottom = menu->top + n_visible() - 1;
  66. int max = n_visible();
  67. if (max > files->count) max = files->count;
  68. int y = (nes_ppu_render_h - (max * 11)) / 2;
  69. for ( int n = menu->top;
  70. n < files->count && n <= bottom;
  71. ++n, y += 11 ) {
  72. char filename[100];
  73. fix_filename(filename, sizeof(filename) - 1,
  74. files->files[n]);
  75. nese_draw_text(
  76. plat,
  77. ( (menu->top == n && 0 != menu->top) ||
  78. (bottom == n && files->count - 1 > bottom) ) ?
  79. "..." : filename,
  80. x, y,
  81. (menu->cursor == n) ?
  82. color_white : menu_colors[n % 6]
  83. );
  84. if (menu->cursor == n) {
  85. nese_draw_text(plat, ">", x - 10, y, color_white);
  86. }
  87. }
  88. nese_draw_finish(plat);
  89. }
  90. nese_Action run_menu(void* plat, Menu_State* state,
  91. const File_List* files, int x) {
  92. Menu_State menu = {0};
  93. if (NULL != state) {
  94. menu = *state;
  95. if (menu.cursor < 0) {
  96. menu.cursor = 0;
  97. } else if (menu.cursor >= files->count) {
  98. menu.cursor = files->count - 1;
  99. }
  100. }
  101. nese_Action action = Action_OK;
  102. while (Action_OK == action) {
  103. // Scrolling (do this first to ensure menu is valid)
  104. const int visible = n_visible() - 1;
  105. menu.top = menu.cursor - (visible / 2);
  106. if (menu.top <= 0) {
  107. // We use <= so we don't readjust the top from 0
  108. menu.top = 0;
  109. } else if (menu.top + visible >= files->count) {
  110. menu.top = (files->count - 1) - visible;
  111. }
  112. show_menu(plat, &menu, files, x);
  113. uint8_t buttons = 0;
  114. action = wait_for_input(plat, &buttons);
  115. if (Action_Menu == action) {
  116. action = Action_Cancel;
  117. } else if (Action_OK == action) {
  118. if (buttons & (1 << Button_B)) {
  119. action = Action_Cancel;
  120. break;
  121. } else if (buttons & ( (1 << Button_A) |
  122. (1 << Button_Start) )) {
  123. // Select
  124. break;
  125. } else if (buttons & (1 << Button_Up)) {
  126. if (menu.cursor > 0) --menu.cursor;
  127. } else if (buttons & ( (1 << Button_Down) |
  128. (1 << Button_Select) )) {
  129. if (menu.cursor < (files->count - 1)) {
  130. ++menu.cursor;
  131. } else if (buttons & (1 << Button_Select)) {
  132. // Wrap around on Select
  133. menu.cursor = 0;
  134. }
  135. }
  136. } else if (Action_Quit != action && Action_Cancel != action) {
  137. // Ignore anything that isn't "Menu", "Cancel" or "Quit"
  138. action = Action_OK;
  139. }
  140. }
  141. if (NULL != state) *state = menu;
  142. wait_for_input_quiet(plat);
  143. return action;
  144. }