| // Copyright 2023 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| #include <cstdint> |
| |
| #define PW_LOG_MODULE_NAME "SnakeGame" |
| #define PW_LOG_LEVEL PW_LOG_LEVEL_DEBUG |
| |
| #include "app_common/common.h" |
| #include "graphics/surface.hpp" |
| #include "libkudzu/framecounter.h" |
| #include "pw_assert/check.h" |
| #include "pw_board_led/led.h" |
| #include "pw_display/display.h" |
| #include "pw_framebuffer/framebuffer.h" |
| #include "pw_log/log.h" |
| #include "pw_system/target_hooks.h" |
| #include "pw_system/work_queue.h" |
| #include "pw_thread/detached_thread.h" |
| #include "pw_thread/thread_core.h" |
| #include "pw_touchscreen/buttons.h" |
| #include "pw_touchscreen/touchscreen.h" |
| #include "snake/game.h" |
| |
| namespace { |
| |
| class PollingTouchButtonsThread : public pw::thread::ThreadCore { |
| public: |
| PollingTouchButtonsThread( |
| pw::touchscreen::Touchscreen& touchscreen, |
| pw::touchscreen::DirectionButtonListener& button_listener, |
| int32_t display_width, |
| int32_t display_height) |
| : touchscreen_(touchscreen), |
| buttons_(button_listener, display_width, display_height) {} |
| |
| void Run() override { |
| while (true) { |
| pw::touchscreen::TouchEvent touch_event = touchscreen_.GetTouchPoint(); |
| buttons_.OnTouchEvent(touch_event); |
| } |
| } |
| |
| private: |
| pw::touchscreen::Touchscreen& touchscreen_; |
| pw::touchscreen::DirectionTouchButtons buttons_; |
| }; |
| |
| void MainTask(void*) { |
| pw::board_led::Init(); |
| PW_CHECK_OK(Common::Init()); |
| |
| pw::display::Display& display = Common::GetDisplay(); |
| pw::framebuffer::Framebuffer framebuffer = display.GetFramebuffer(); |
| PW_CHECK(framebuffer.is_valid()); |
| |
| blit::Surface screen = blit::Surface( |
| static_cast<uint8_t*>(framebuffer.data()), |
| blit::PixelFormat::RGB565, |
| blit::Size(framebuffer.size().width, framebuffer.size().height)); |
| screen.pen = blit::Pen(0, 0, 0, 255); |
| screen.clear(); |
| |
| const auto display_width = framebuffer.size().width; |
| const auto display_height = framebuffer.size().height; |
| display.ReleaseFramebuffer(std::move(framebuffer)); |
| |
| snake::Game game(display_width, display_height); |
| PollingTouchButtonsThread touch_buttons_thread{ |
| Common::GetTouchscreen(), game, display_width, display_height}; |
| pw::thread::DetachedThread(Common::TouchscreenThreadOptions(), |
| touch_buttons_thread); |
| |
| game.Start(); |
| |
| // Display and app loop. |
| kudzu::FrameCounter frame_counter = kudzu::FrameCounter(); |
| while (true) { |
| frame_counter.StartFrame(); |
| |
| // Get frame buffer. |
| framebuffer = display.GetFramebuffer(); |
| PW_CHECK(framebuffer.is_valid()); |
| screen.data = static_cast<uint8_t*>(framebuffer.data()); |
| // Clear the screen |
| screen.pen = blit::Pen(0, 0, 0); |
| screen.clear(); |
| |
| // Let game draw its frame. |
| game.OnFrame(framebuffer); |
| |
| // Update timers |
| frame_counter.EndDraw(); |
| |
| display.ReleaseFramebuffer(std::move(framebuffer)); |
| frame_counter.EndFlush(); |
| |
| frame_counter.LogTiming(); |
| } |
| } |
| |
| } // namespace |
| |
| namespace pw::system { |
| |
| void UserAppInit() { |
| PW_LOG_INFO("UserAppInit"); |
| pw::thread::DetachedThread(Common::DisplayDrawThreadOptions(), MainTask); |
| } |
| |
| } // namespace pw::system |