Fix frame update logic and emulator support
- Fix basic1.cpp loop to handle set_frame_updates(true) correctly with sleep - Update emulator loop for concurrent input and frame updates - Update emulator for SFML 3.0 compatibility - Add INPUT.FRAME_TICK constant to Lua bindings - Enable frame updates in snake.lua example
This commit is contained in:
33
basic1.cpp
33
basic1.cpp
@@ -552,8 +552,21 @@ int main()
|
|||||||
uint32_t game_start_time = 0;
|
uint32_t game_start_time = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
// Determine if we should sleep or stay awake for updates
|
||||||
|
bool stay_awake = false;
|
||||||
|
if (pending_refresh) stay_awake = true;
|
||||||
|
|
||||||
|
if (launcher.is_game_selected()) {
|
||||||
|
Game* g = launcher.get_selected_game();
|
||||||
|
if (g && g->wants_frame_updates()) {
|
||||||
|
stay_awake = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stay_awake) {
|
||||||
// Sleep until interrupt wakes us up (very power efficient!)
|
// Sleep until interrupt wakes us up (very power efficient!)
|
||||||
__wfi(); // Wait For Interrupt - CPU sleeps until any interrupt occurs
|
__wfi(); // Wait For Interrupt - CPU sleeps until any interrupt occurs
|
||||||
|
}
|
||||||
|
|
||||||
InputEvent input = {INPUT_NONE, 0, 0, 0, 0, 0, false};
|
InputEvent input = {INPUT_NONE, 0, 0, 0, 0, 0, false};
|
||||||
bool needs_refresh = false;
|
bool needs_refresh = false;
|
||||||
@@ -639,18 +652,24 @@ int main()
|
|||||||
}
|
}
|
||||||
needs_refresh = true;
|
needs_refresh = true;
|
||||||
}
|
}
|
||||||
} else if (launcher.is_game_selected()) {
|
}
|
||||||
|
|
||||||
|
if (launcher.is_game_selected()) {
|
||||||
// No input, but check if game wants continuous updates
|
// No input, but check if game wants continuous updates
|
||||||
current_game = launcher.get_selected_game();
|
current_game = launcher.get_selected_game();
|
||||||
if (current_game->wants_frame_updates()) {
|
if (current_game->wants_frame_updates()) {
|
||||||
// Send frame tick event for animation/physics updates
|
// Only send frame tick if we're ready to draw the next frame
|
||||||
|
if (!is_refresh_in_progress()) {
|
||||||
InputEvent frame_tick = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
InputEvent frame_tick = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
||||||
needs_refresh = current_game->update(frame_tick);
|
needs_refresh = current_game->update(frame_tick) || needs_refresh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Redraw and queue async refresh on Core 1
|
// 4. Redraw and queue async refresh on Core 1
|
||||||
if (needs_refresh || pending_refresh) {
|
if (needs_refresh || pending_refresh) {
|
||||||
|
// Only draw if Core 1 is finished with the buffer
|
||||||
|
if (!is_refresh_in_progress()) {
|
||||||
// Clear buffer and redraw entire UI with updated state
|
// Clear buffer and redraw entire UI with updated state
|
||||||
memset(bit_buffer, 0, V_WIDTH * V_HEIGHT / 8);
|
memset(bit_buffer, 0, V_WIDTH * V_HEIGHT / 8);
|
||||||
|
|
||||||
@@ -667,13 +686,11 @@ int main()
|
|||||||
if (refresh_started) {
|
if (refresh_started) {
|
||||||
pending_refresh = false; // Refresh queued successfully
|
pending_refresh = false; // Refresh queued successfully
|
||||||
} else {
|
} else {
|
||||||
pending_refresh = true; // Core 1 busy, retry next iteration
|
pending_refresh = true;
|
||||||
if (config.debug_verbose) {
|
|
||||||
printf("Refresh pending - Core 1 still busy\n");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pending_refresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core 0 continues immediately, Core 1 handles the refresh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Check if display should be dimmed due to inactivity
|
// 5. Check if display should be dimmed due to inactivity
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ extern Font font_5x5_obj;
|
|||||||
GameLauncher::GameLauncher(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
|
GameLauncher::GameLauncher(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
|
||||||
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager),
|
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager),
|
||||||
selected_index(0), selected_game(nullptr) {}
|
selected_index(0), selected_game(nullptr) {}
|
||||||
void GameLauncher::register_game(const char* name, const char* description, Game* (*factory)(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*)) {
|
void GameLauncher::register_game(const char* name, const char* description,
|
||||||
|
std::function<Game*(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*)> factory) {
|
||||||
GameEntry entry;
|
GameEntry entry;
|
||||||
entry.name = name;
|
entry.name = name;
|
||||||
entry.description = description;
|
entry.description = description;
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ int main() {
|
|||||||
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};
|
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};
|
||||||
|
|
||||||
while (const auto sfEvent = display.pollEvent()) {
|
while (const auto sfEvent = display.pollEvent()) {
|
||||||
if (const auto* closed = sfEvent->getIf<sf::Event::Closed>()) {
|
if (sfEvent->is<sf::Event::Closed>()) {
|
||||||
display.close();
|
display.close();
|
||||||
running = false;
|
running = false;
|
||||||
} else if (const auto* mousePressed = sfEvent->getIf<sf::Event::MouseButtonPressed>()) {
|
} else if (const auto* mouse = sfEvent->getIf<sf::Event::MouseButtonPressed>()) {
|
||||||
event.type = INPUT_TOUCH_DOWN;
|
event.type = INPUT_TOUCH_DOWN;
|
||||||
event.x = mousePressed->position.x;
|
event.x = mouse->position.x;
|
||||||
event.y = mousePressed->position.y;
|
event.y = mouse->position.y;
|
||||||
event.valid = true;
|
event.valid = true;
|
||||||
|
|
||||||
// Check for virtual buttons
|
// Check for virtual buttons
|
||||||
@@ -76,14 +76,14 @@ int main() {
|
|||||||
if (input_manager.check_virtual_buttons(event.x, event.y, virtual_type)) {
|
if (input_manager.check_virtual_buttons(event.x, event.y, virtual_type)) {
|
||||||
event.type = virtual_type;
|
event.type = virtual_type;
|
||||||
}
|
}
|
||||||
} else if (const auto* keyPressed = sfEvent->getIf<sf::Event::KeyPressed>()) {
|
} else if (const auto* key = sfEvent->getIf<sf::Event::KeyPressed>()) {
|
||||||
if (keyPressed->code == sf::Keyboard::Key::Space) {
|
if (key->code == sf::Keyboard::Key::Space) {
|
||||||
event.type = INPUT_BUTTON_0;
|
event.type = INPUT_BUTTON_0;
|
||||||
event.valid = true;
|
event.valid = true;
|
||||||
} else if (keyPressed->code == sf::Keyboard::Key::Enter) {
|
} else if (key->code == sf::Keyboard::Key::Enter) {
|
||||||
event.type = INPUT_BUTTON_1;
|
event.type = INPUT_BUTTON_1;
|
||||||
event.valid = true;
|
event.valid = true;
|
||||||
} else if (keyPressed->code == sf::Keyboard::Key::Escape) {
|
} else if (key->code == sf::Keyboard::Key::Escape) {
|
||||||
// Simulate long-press exit
|
// Simulate long-press exit
|
||||||
if (launcher.is_game_selected()) {
|
if (launcher.is_game_selected()) {
|
||||||
launcher.reset();
|
launcher.reset();
|
||||||
@@ -107,8 +107,10 @@ int main() {
|
|||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (launcher.is_game_selected()) {
|
}
|
||||||
// No user input, but check if game wants frame tick updates
|
|
||||||
|
// Check if game wants frame tick updates (independent of user input)
|
||||||
|
if (launcher.is_game_selected()) {
|
||||||
current_game = launcher.get_selected_game();
|
current_game = launcher.get_selected_game();
|
||||||
if (current_game->wants_frame_updates()) {
|
if (current_game->wants_frame_updates()) {
|
||||||
InputEvent frame_event = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
InputEvent frame_event = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
||||||
|
|||||||
@@ -237,6 +237,10 @@ static void register_input_constants(lua_State* L) {
|
|||||||
lua_pushinteger(L, 6);
|
lua_pushinteger(L, 6);
|
||||||
lua_settable(L, -3);
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "FRAME_TICK");
|
||||||
|
lua_pushinteger(L, 7);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
lua_setglobal(L, "INPUT");
|
lua_setglobal(L, "INPUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ function init()
|
|||||||
game.vars.frame_count = 0
|
game.vars.frame_count = 0
|
||||||
game.vars.move_speed = 10 -- Frames between moves
|
game.vars.move_speed = 10 -- Frames between moves
|
||||||
|
|
||||||
|
-- Enable continuous frame updates
|
||||||
|
game.set_frame_updates(true)
|
||||||
|
|
||||||
print("Snake Game initialized")
|
print("Snake Game initialized")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user