GameLoop.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. notification_app = (NotificationApp *) furi_record_open(RECORD_NOTIFICATION);
  14. notification_message_block(notification_app, &sequence_display_backlight_enforce_on);
  15. logic = new GameLogic(buffer, &inputHandler, notification_app);
  16. if (!render_mutex) {
  17. return;
  18. }
  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 && event->key == InputKeyBack) {
  28. inst->processing = false;
  29. }
  30. }
  31. int32_t GameLoop::render_thread(void *ctx) {
  32. auto *inst = (GameLoop *) ctx;
  33. uint32_t last_tick = 0;
  34. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  35. while (inst->renderRunning) {
  36. uint32_t tick = furi_get_tick();
  37. if (inst->logic->dirty) {
  38. if(furi_mutex_acquire(inst->render_mutex, 20) == FuriStatusOk) {
  39. inst->logic->dirty = false;
  40. inst->logic->Update((tick - last_tick) / 1000.0f);
  41. last_tick = tick;
  42. furi_mutex_release(inst->render_mutex);
  43. }
  44. }
  45. furi_thread_yield();
  46. }
  47. return 0;
  48. }
  49. char timeString[24];
  50. void GameLoop::Start() {
  51. if (!render_mutex) {
  52. return;
  53. }
  54. furi_thread_start(buffer_thread_ptr);
  55. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  56. while (processing) {
  57. if (logic->isReady()) {
  58. furi_mutex_acquire(render_mutex, FuriWaitForever);
  59. buffer->render(canvas);
  60. if(logic->end>0 &&logic->state == Logo){
  61. int diff = logic->end - logic->startTime;
  62. if(diff>0) {
  63. int hours = diff / 3600000;
  64. int minutes = (diff % 3600000) / 60000;
  65. int seconds = (diff % 60000) / 1000;
  66. snprintf(timeString, sizeof(timeString), "Completed: %02d:%02d:%02d", hours, minutes, seconds);
  67. canvas_set_font(canvas, FontSecondary);
  68. canvas_draw_str_aligned(canvas, 60, 5, AlignCenter, AlignTop, timeString);
  69. }
  70. }
  71. furi_mutex_release(render_mutex);
  72. canvas_commit(canvas);
  73. }
  74. furi_thread_yield();
  75. }
  76. }
  77. GameLoop::~GameLoop() {
  78. notification_message_block(notification_app, &sequence_display_backlight_enforce_auto);
  79. furi_pubsub_unsubscribe(input, input_subscription);
  80. renderRunning = false;
  81. furi_thread_join(buffer_thread_ptr);
  82. furi_thread_free(buffer_thread_ptr);
  83. canvas = NULL;
  84. gui_direct_draw_release(gui);
  85. furi_record_close(RECORD_GUI);
  86. furi_record_close(RECORD_INPUT_EVENTS);
  87. furi_record_close(RECORD_NOTIFICATION);
  88. furi_mutex_free(render_mutex);
  89. delete logic;
  90. delete buffer;
  91. }