GameLoop.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #include <dolphin/dolphin.h>
  2. #include <notification/notification_messages.h>
  3. #include "GameLoop.h"
  4. GameLoop::GameLoop() {
  5. inputHandler = InputEventHandler();
  6. dolphin_deed(DolphinDeedPluginGameStart);
  7. input = (FuriPubSub *) furi_record_open(RECORD_INPUT_EVENTS);
  8. gui = (Gui *) furi_record_open(RECORD_GUI);
  9. canvas = gui_direct_draw_acquire(gui);
  10. input_subscription = furi_pubsub_subscribe(input, &input_callback, this);
  11. buffer = new RenderBuffer(128, 64);
  12. render_mutex = (FuriMutex *) furi_mutex_alloc(FuriMutexTypeNormal);
  13. logic = new GameLogic(buffer, &inputHandler);
  14. if (!render_mutex) {
  15. return;
  16. }
  17. notification_app = (NotificationApp *) furi_record_open(RECORD_NOTIFICATION);
  18. notification_message_block(notification_app, &sequence_display_backlight_enforce_on);
  19. buffer_thread_ptr = furi_thread_alloc_ex(
  20. "BackBufferThread", 3 * 1024, render_thread, this);
  21. }
  22. void GameLoop::input_callback(const void *value, void *ctx) {
  23. auto *inst = (GameLoop *) ctx;
  24. const auto *event = (const InputEvent *) value;
  25. inst->inputHandler.Set(event->key, event->type);
  26. inst->logic->dirty = event->type != InputTypePress;
  27. if (event->type == InputTypeLong) {
  28. FURI_LOG_I("INPUT", "LONG INPUT %i", event->key);
  29. }
  30. if (event->type == InputTypeLong && event->key == InputKeyBack) {
  31. inst->processing = false;
  32. }
  33. }
  34. int32_t GameLoop::render_thread(void *ctx) {
  35. auto *inst = (GameLoop *) ctx;
  36. uint32_t last_tick = 0;
  37. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  38. while (inst->renderRunning) {
  39. uint32_t tick = furi_get_tick();
  40. if (inst->logic->dirty) {
  41. if(furi_mutex_acquire(inst->render_mutex, 20) == FuriStatusOk) {
  42. inst->logic->dirty = false;
  43. inst->logic->Update((tick - last_tick) / 1000.0f);
  44. last_tick = tick;
  45. furi_mutex_release(inst->render_mutex);
  46. }
  47. }
  48. furi_thread_yield();
  49. }
  50. return 0;
  51. }
  52. char timeString[24];
  53. void GameLoop::Start() {
  54. if (!render_mutex) {
  55. return;
  56. }
  57. furi_thread_start(buffer_thread_ptr);
  58. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  59. while (processing) {
  60. if (logic->isReady()) {
  61. furi_mutex_acquire(render_mutex, FuriWaitForever);
  62. buffer->render(canvas);
  63. if(logic->end>0 &&logic->state == Logo){
  64. int diff = logic->end - logic->startTime;
  65. if(diff>0) {
  66. int hours = diff / 3600000;
  67. int minutes = (diff % 3600000) / 60000;
  68. int seconds = (diff % 60000) / 1000;
  69. snprintf(timeString, sizeof(timeString), "Completed: %02d:%02d:%02d", hours, minutes, seconds);
  70. canvas_set_font(canvas, FontSecondary);
  71. canvas_draw_str_aligned(canvas, 60, 5, AlignCenter, AlignTop, timeString);
  72. }
  73. }
  74. furi_mutex_release(render_mutex);
  75. canvas_commit(canvas);
  76. }
  77. furi_thread_yield();
  78. }
  79. }
  80. GameLoop::~GameLoop() {
  81. notification_message_block(notification_app, &sequence_display_backlight_enforce_auto);
  82. furi_pubsub_unsubscribe(input, input_subscription);
  83. renderRunning = false;
  84. furi_thread_join(buffer_thread_ptr);
  85. furi_thread_free(buffer_thread_ptr);
  86. canvas = NULL;
  87. gui_direct_draw_release(gui);
  88. furi_record_close(RECORD_GUI);
  89. furi_record_close(RECORD_INPUT_EVENTS);
  90. furi_record_close(RECORD_NOTIFICATION);
  91. furi_mutex_free(render_mutex);
  92. delete logic;
  93. delete buffer;
  94. }