GameLoop.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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. void GameLoop::Start() {
  53. dolphin_deed(DolphinDeedPluginGameStart);
  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. canvas_commit(canvas);
  64. furi_mutex_release(render_mutex);
  65. }
  66. furi_thread_yield();
  67. }
  68. }
  69. GameLoop::~GameLoop() {
  70. notification_message_block(notification_app, &sequence_display_backlight_enforce_auto);
  71. furi_pubsub_unsubscribe(input, input_subscription);
  72. renderRunning = false;
  73. furi_thread_join(buffer_thread_ptr);
  74. furi_thread_free(buffer_thread_ptr);
  75. canvas = NULL;
  76. gui_direct_draw_release(gui);
  77. furi_record_close(RECORD_GUI);
  78. furi_record_close(RECORD_INPUT_EVENTS);
  79. furi_record_close(RECORD_NOTIFICATION);
  80. furi_mutex_free(render_mutex);
  81. delete logic;
  82. delete buffer;
  83. }