|
@@ -1,10 +1,11 @@
|
|
|
-#include "fgeo.h"
|
|
|
|
|
|
|
+#include "game_engine.h"
|
|
|
#include <furi.h>
|
|
#include <furi.h>
|
|
|
#include <gui/gui.h>
|
|
#include <gui/gui.h>
|
|
|
#include <input/input.h>
|
|
#include <input/input.h>
|
|
|
-
|
|
|
|
|
#include "clock_timer.h"
|
|
#include "clock_timer.h"
|
|
|
|
|
|
|
|
|
|
+typedef _Atomic uint32_t AtomicUint32;
|
|
|
|
|
+
|
|
|
GameEngineSettings game_engine_settings_init() {
|
|
GameEngineSettings game_engine_settings_init() {
|
|
|
GameEngineSettings settings;
|
|
GameEngineSettings settings;
|
|
|
settings.fps = 60.0f;
|
|
settings.fps = 60.0f;
|
|
@@ -27,20 +28,6 @@ typedef enum {
|
|
|
|
|
|
|
|
#define GameThreadFlagMask (GameThreadFlagUpdate | GameThreadFlagStop)
|
|
#define GameThreadFlagMask (GameThreadFlagUpdate | GameThreadFlagStop)
|
|
|
|
|
|
|
|
-static void clock_timer_tick(void* context) {
|
|
|
|
|
- GameEngine* engine = context;
|
|
|
|
|
- furi_thread_flags_set(engine->thread_id, GameThreadFlagUpdate);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-static void input_events_callback(const void* value, void* context) {
|
|
|
|
|
- GameEngine* engine = context;
|
|
|
|
|
-
|
|
|
|
|
- const InputEvent* event = value;
|
|
|
|
|
- if(event->key == InputKeyBack && event->type == InputTypePress) {
|
|
|
|
|
- furi_thread_flags_set(engine->thread_id, GameThreadFlagStop);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
GameEngine* game_engine_alloc(GameEngineSettings settings) {
|
|
GameEngine* game_engine_alloc(GameEngineSettings settings) {
|
|
|
GameEngine* engine = malloc(sizeof(GameEngine));
|
|
GameEngine* engine = malloc(sizeof(GameEngine));
|
|
|
engine->gui = furi_record_open(RECORD_GUI);
|
|
engine->gui = furi_record_open(RECORD_GUI);
|
|
@@ -70,15 +57,47 @@ static void canvas_printf(Canvas* canvas, uint8_t x, uint8_t y, const char* form
|
|
|
furi_string_free(string);
|
|
furi_string_free(string);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void clock_timer_callback(void* context) {
|
|
|
|
|
+ GameEngine* engine = context;
|
|
|
|
|
+ furi_thread_flags_set(engine->thread_id, GameThreadFlagUpdate);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void input_events_callback(const void* value, void* context) {
|
|
|
|
|
+ AtomicUint32* input_state = context;
|
|
|
|
|
+
|
|
|
|
|
+ const InputEvent* event = value;
|
|
|
|
|
+ if(event->type == InputTypePress) {
|
|
|
|
|
+ *input_state |= (1 << event->key);
|
|
|
|
|
+ } else if(event->type == InputTypeRelease) {
|
|
|
|
|
+ *input_state &= ~(1 << event->key);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+typedef struct {
|
|
|
|
|
+ uint32_t current;
|
|
|
|
|
+ uint32_t pressed;
|
|
|
|
|
+ uint32_t released;
|
|
|
|
|
+} InputState;
|
|
|
|
|
+
|
|
|
void game_engine_run(GameEngine* engine) {
|
|
void game_engine_run(GameEngine* engine) {
|
|
|
engine->running = true;
|
|
engine->running = true;
|
|
|
|
|
+
|
|
|
|
|
+ // input state
|
|
|
|
|
+ AtomicUint32 input_state = 0;
|
|
|
|
|
+ uint32_t input_prev_state = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // acquire gui canvas
|
|
|
Canvas* canvas = gui_direct_draw_acquire(engine->gui);
|
|
Canvas* canvas = gui_direct_draw_acquire(engine->gui);
|
|
|
|
|
+
|
|
|
|
|
+ // subscribe to input events
|
|
|
FuriPubSubSubscription* input_subscription =
|
|
FuriPubSubSubscription* input_subscription =
|
|
|
- furi_pubsub_subscribe(engine->input_pubsub, input_events_callback, engine);
|
|
|
|
|
|
|
+ furi_pubsub_subscribe(engine->input_pubsub, input_events_callback, &input_state);
|
|
|
|
|
|
|
|
- clock_timer_init(clock_timer_tick, engine, engine->settings.fps);
|
|
|
|
|
|
|
+ // start "game update" timer
|
|
|
|
|
+ clock_timer_init(clock_timer_callback, engine, engine->settings.fps);
|
|
|
clock_timer_start();
|
|
clock_timer_start();
|
|
|
|
|
|
|
|
|
|
+ // init fps counter
|
|
|
uint32_t time_start = DWT->CYCCNT;
|
|
uint32_t time_start = DWT->CYCCNT;
|
|
|
|
|
|
|
|
while(true) {
|
|
while(true) {
|
|
@@ -87,6 +106,14 @@ void game_engine_run(GameEngine* engine) {
|
|
|
furi_check((flags & FuriFlagError) == 0);
|
|
furi_check((flags & FuriFlagError) == 0);
|
|
|
|
|
|
|
|
if(flags & GameThreadFlagUpdate) {
|
|
if(flags & GameThreadFlagUpdate) {
|
|
|
|
|
+ uint32_t input_current_state = input_state;
|
|
|
|
|
+ InputState input = {
|
|
|
|
|
+ .current = input_current_state,
|
|
|
|
|
+ .pressed = input_current_state & ~input_prev_state,
|
|
|
|
|
+ .released = ~input_current_state & input_prev_state,
|
|
|
|
|
+ };
|
|
|
|
|
+ input_prev_state = input_current_state;
|
|
|
|
|
+
|
|
|
canvas_reset(canvas);
|
|
canvas_reset(canvas);
|
|
|
|
|
|
|
|
uint32_t time_end = DWT->CYCCNT;
|
|
uint32_t time_end = DWT->CYCCNT;
|
|
@@ -99,6 +126,14 @@ void game_engine_run(GameEngine* engine) {
|
|
|
canvas_printf(canvas, 0, 7, "%u", (uint32_t)roundf(fps));
|
|
canvas_printf(canvas, 0, 7, "%u", (uint32_t)roundf(fps));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if(input.pressed != 0) {
|
|
|
|
|
+ FURI_LOG_I("input", "pressed: %lu", input.pressed);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(input.released != 0) {
|
|
|
|
|
+ FURI_LOG_I("input", "released: %lu", input.released);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
canvas_commit(canvas);
|
|
canvas_commit(canvas);
|
|
|
} else if(flags & GameThreadFlagStop) {
|
|
} else if(flags & GameThreadFlagStop) {
|
|
|
break;
|
|
break;
|
|
@@ -112,3 +147,7 @@ void game_engine_run(GameEngine* engine) {
|
|
|
furi_pubsub_unsubscribe(engine->input_pubsub, input_subscription);
|
|
furi_pubsub_unsubscribe(engine->input_pubsub, input_subscription);
|
|
|
engine->running = false;
|
|
engine->running = false;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+void game_engine_stop(GameEngine* engine) {
|
|
|
|
|
+ furi_thread_flags_set(engine->thread_id, GameThreadFlagStop);
|
|
|
|
|
+}
|