solitaire.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <notification/notification_messages.h>
  5. #include "game_state.h"
  6. #include "src/util/list.h"
  7. #include "src/scene/scene_setup.h"
  8. #include "src/util/helpers.h"
  9. static List *game_logic;
  10. static ListItem *current_state;
  11. static FuriMutex *update_mutex;
  12. static void gui_input_events_callback(const void *value, void *ctx) {
  13. furi_mutex_acquire(update_mutex, FuriWaitForever);
  14. GameState *instance = ctx;
  15. const InputEvent *event = value;
  16. if (event->key == InputKeyBack && event->type == InputTypeLong) {
  17. FURI_LOG_W("INPUT", "EXIT");
  18. instance->exit = true;
  19. }
  20. if (current_state) {
  21. ((GameLogic *) current_state->data)->input(instance, event->key, event->type);
  22. }
  23. furi_mutex_release(update_mutex);
  24. }
  25. static GameState *prepare() {
  26. game_logic = list_make();
  27. update_mutex = (FuriMutex *) furi_mutex_alloc(FuriMutexTypeNormal);
  28. //Add scenes to the logic list
  29. list_push_back(&main_screen, game_logic);
  30. list_push_back(&intro_screen, game_logic);
  31. list_push_back(&play_screen, game_logic);
  32. list_push_back(&solve_screen, game_logic);
  33. list_push_back(&falling_screen, game_logic);
  34. list_push_back(&result_screen, game_logic);
  35. current_state = game_logic->head;
  36. GameState *instance = malloc(sizeof(GameState));
  37. ((GameLogic *) current_state->data)->start(instance);
  38. instance->hand = list_make();
  39. instance->deck = list_make();
  40. instance->waste = list_make();
  41. for (int i = 0; i < 7; i++) {
  42. if (i < 4) {
  43. instance->foundation[i] = list_make();
  44. }
  45. instance->tableau[i] = list_make();
  46. }
  47. instance->animated_card.position = VECTOR_ZERO;
  48. instance->animated_card.velocity = VECTOR_ZERO;
  49. instance->buffer = buffer_create(SCREEN_WIDTH, SCREEN_HEIGHT, false);
  50. instance->input = furi_record_open(RECORD_INPUT_EVENTS);
  51. instance->gui = furi_record_open(RECORD_GUI);
  52. instance->canvas = gui_direct_draw_acquire(instance->gui);
  53. instance->notification_app = (NotificationApp *) furi_record_open(RECORD_NOTIFICATION);
  54. notification_message_block(instance->notification_app, &sequence_display_backlight_enforce_on);
  55. instance->input_subscription =
  56. furi_pubsub_subscribe(instance->input, gui_input_events_callback, instance);
  57. return instance;
  58. }
  59. static void cleanup(GameState *instance) {
  60. furi_pubsub_unsubscribe(instance->input, instance->input_subscription);
  61. notification_message_block(instance->notification_app, &sequence_display_backlight_enforce_auto);
  62. list_free(instance->hand);
  63. list_free(instance->deck);
  64. list_free(instance->waste);
  65. for (int i = 0; i < 7; i++) {
  66. if (i < 4) {
  67. list_free(instance->foundation[i]);
  68. }
  69. list_free(instance->tableau[i]);
  70. }
  71. furi_mutex_free(update_mutex);
  72. instance->canvas = NULL;
  73. gui_direct_draw_release(instance->gui);
  74. furi_record_close(RECORD_GUI);
  75. furi_record_close(RECORD_INPUT_EVENTS);
  76. furi_record_close(RECORD_NOTIFICATION);
  77. list_clear(game_logic);
  78. free(game_logic);
  79. buffer_release(instance->buffer);
  80. free(instance);
  81. }
  82. static void next_scene(GameState *instance) {
  83. FURI_LOG_W("SCENE", "Next scene");
  84. current_state = current_state->next;
  85. if (current_state == NULL) {
  86. current_state = game_logic->head;
  87. }
  88. ((GameLogic *) current_state->data)->start(instance);
  89. }
  90. static void prev_scene(GameState *instance) {
  91. FURI_LOG_W("SCENE", "Prev scene");
  92. current_state = game_logic->head;
  93. if (current_state->prev == NULL) {
  94. instance->exit = true;
  95. return;
  96. }
  97. ((GameLogic *) current_state->data)->start(instance);
  98. }
  99. static void direct_draw_run(GameState *instance) {
  100. if(!check_pointer(instance)) return;
  101. size_t currFrameTime;
  102. size_t lastFrameTime = curr_time();
  103. instance->lateRender = false;
  104. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  105. do {
  106. FuriStatus status = furi_mutex_acquire(update_mutex, 20);
  107. if (!status) continue;
  108. GameLogic *curr_state = (GameLogic *) current_state->data;
  109. currFrameTime = curr_time();
  110. instance->delta_time = (currFrameTime - lastFrameTime) / 64000000.0f;
  111. lastFrameTime = currFrameTime;
  112. check_pointer(curr_state);
  113. curr_state->update(instance);
  114. if (instance->scene_switch == 1) {
  115. next_scene(instance);
  116. } else if (instance->scene_switch == 2) {
  117. prev_scene(instance);
  118. }
  119. check_pointer(curr_state);
  120. check_pointer(instance);
  121. check_pointer(instance->canvas);
  122. check_pointer(instance->buffer);
  123. instance->scene_switch = 0;
  124. if (curr_state && instance->isDirty && instance->canvas && instance->buffer) {
  125. canvas_reset(instance->canvas);
  126. if(instance->lateRender){
  127. buffer_swap_back(instance->buffer);
  128. buffer_render(instance->buffer, instance->canvas);
  129. curr_state->render(instance);
  130. }else{
  131. buffer_swap_back(instance->buffer);
  132. curr_state->render(instance);
  133. buffer_render(instance->buffer, instance->canvas);
  134. }
  135. canvas_commit(instance->canvas);
  136. if (instance->clearBuffer)
  137. buffer_clear(instance->buffer);
  138. instance->clearBuffer = true;
  139. instance->lateRender = false;
  140. instance->isDirty = false;
  141. }
  142. furi_mutex_release(update_mutex);
  143. furi_thread_yield();
  144. } while (!instance->exit);
  145. }
  146. int32_t solitaire_app(void *p) {
  147. UNUSED(p);
  148. int32_t return_code = 0;
  149. GameState *instance = prepare();
  150. direct_draw_run(instance);
  151. cleanup(instance);
  152. return return_code;
  153. }