solitaire.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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(
  62. instance->notification_app, &sequence_display_backlight_enforce_auto);
  63. list_free(instance->hand);
  64. list_free(instance->deck);
  65. list_free(instance->waste);
  66. for(int i = 0; i < 7; i++) {
  67. if(i < 4) {
  68. list_free(instance->foundation[i]);
  69. }
  70. list_free(instance->tableau[i]);
  71. }
  72. furi_mutex_free(update_mutex);
  73. instance->canvas = NULL;
  74. gui_direct_draw_release(instance->gui);
  75. furi_record_close(RECORD_GUI);
  76. furi_record_close(RECORD_INPUT_EVENTS);
  77. list_clear(game_logic);
  78. buffer_release(instance->buffer);
  79. free(instance);
  80. }
  81. static void next_scene(GameState* instance) {
  82. FURI_LOG_W("SCENE", "Next scene");
  83. current_state = current_state->next;
  84. if(current_state == NULL) {
  85. current_state = game_logic->head;
  86. }
  87. ((GameLogic*)current_state->data)->start(instance);
  88. }
  89. static void prev_scene(GameState* instance) {
  90. FURI_LOG_W("SCENE", "Prev scene");
  91. current_state = game_logic->head;
  92. if(current_state->prev == NULL) {
  93. instance->exit = true;
  94. return;
  95. }
  96. ((GameLogic*)current_state->data)->start(instance);
  97. }
  98. static void direct_draw_run(GameState* instance) {
  99. if(!check_pointer(instance)) return;
  100. size_t currFrameTime;
  101. size_t lastFrameTime = curr_time();
  102. instance->lateRender = false;
  103. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  104. do {
  105. FuriStatus status = furi_mutex_acquire(update_mutex, 20);
  106. if(!status) continue;
  107. GameLogic* curr_state = (GameLogic*)current_state->data;
  108. currFrameTime = curr_time();
  109. instance->delta_time = (currFrameTime - lastFrameTime) / 64000000.0f;
  110. lastFrameTime = currFrameTime;
  111. check_pointer(curr_state);
  112. curr_state->update(instance);
  113. if(instance->scene_switch == 1) {
  114. next_scene(instance);
  115. } else if(instance->scene_switch == 2) {
  116. prev_scene(instance);
  117. }
  118. check_pointer(curr_state);
  119. check_pointer(instance);
  120. check_pointer(instance->canvas);
  121. check_pointer(instance->buffer);
  122. instance->scene_switch = 0;
  123. if(curr_state && instance->isDirty && instance->canvas && instance->buffer) {
  124. canvas_reset(instance->canvas);
  125. if(instance->lateRender) {
  126. buffer_swap_back(instance->buffer);
  127. buffer_render(instance->buffer, instance->canvas);
  128. curr_state->render(instance);
  129. } else {
  130. curr_state->render(instance);
  131. buffer_swap_back(instance->buffer);
  132. buffer_render(instance->buffer, instance->canvas);
  133. }
  134. canvas_commit(instance->canvas);
  135. if(instance->clearBuffer) buffer_clear(instance->buffer);
  136. instance->clearBuffer = true;
  137. instance->lateRender = false;
  138. instance->isDirty = false;
  139. }
  140. furi_mutex_release(update_mutex);
  141. furi_thread_yield();
  142. } while(!instance->exit);
  143. }
  144. int32_t solitaire_app(void* p) {
  145. UNUSED(p);
  146. int32_t return_code = 0;
  147. GameState* instance = prepare();
  148. direct_draw_run(instance);
  149. cleanup(instance);
  150. return return_code;
  151. }