-
-
Notifications
You must be signed in to change notification settings - Fork 19.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
✨ Games for E3V2 + MarlinUI (#27620)
Showing
15 changed files
with
808 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/** | ||
* Marlin 3D Printer Firmware | ||
* Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||
* | ||
* Based on Sprinter and grbl. | ||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
#include "../../inc/MarlinConfigPre.h" | ||
|
||
#if HAS_MARLINUI_U8GLIB && HAS_GAMES | ||
|
||
#include "../menu/game/types.h" // includes dogm/game.h | ||
|
||
void MarlinGame::frame_start() { | ||
set_color(color::WHITE); | ||
} | ||
|
||
void MarlinGame::frame_end() {} | ||
|
||
void MarlinGame::set_color(const color color) { | ||
switch (color) { | ||
default: | ||
case color::WHITE: u8g.setColorIndex(1); break; | ||
case color::BLACK: u8g.setColorIndex(0); break; | ||
} | ||
} | ||
|
||
void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) { | ||
u8g.drawHLine(x, y, w); | ||
} | ||
|
||
void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) { | ||
u8g.drawVLine(x, y, h); | ||
} | ||
|
||
void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { | ||
u8g.drawFrame(x, y, w, h); | ||
} | ||
|
||
void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { | ||
u8g.drawBox(x, y, w, h); | ||
} | ||
|
||
void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) { | ||
u8g.drawPixel(x, y); | ||
} | ||
|
||
void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) { | ||
u8g.drawBitmapP(x, y, bytes_per_row, rows, bitmap); | ||
} | ||
|
||
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) { | ||
lcd_moveto(x, y); | ||
return lcd_put_u8str_P(str); | ||
} | ||
|
||
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const fstr) { | ||
lcd_moveto(x, y); | ||
return lcd_put_u8str(fstr); | ||
} | ||
|
||
void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) { | ||
lcd_put_int(x, y, value); | ||
} | ||
|
||
#endif // HAS_MARLINUI_U8GLIB && HAS_GAMES |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* Marlin 3D Printer Firmware | ||
* Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||
* | ||
* Based on Sprinter and grbl. | ||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
#pragma once | ||
|
||
#include "marlinui_DOGM.h" | ||
#include "../lcdprint.h" | ||
|
||
typedef uint8_t game_dim_t; | ||
typedef const u8g_pgm_uint8_t* pgm_bitmap_t; | ||
|
||
constexpr game_dim_t GAME_WIDTH = LCD_PIXEL_WIDTH; | ||
constexpr game_dim_t GAME_HEIGHT = LCD_PIXEL_HEIGHT; | ||
constexpr game_dim_t GAME_FONT_WIDTH = MENU_FONT_WIDTH; | ||
constexpr game_dim_t GAME_FONT_ASCENT = MENU_FONT_ASCENT; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
/** | ||
* Marlin 3D Printer Firmware | ||
* Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||
* | ||
* Based on Sprinter and grbl. | ||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
#include "../../../inc/MarlinConfigPre.h" | ||
|
||
#if IS_DWIN_MARLINUI && HAS_GAMES | ||
|
||
// Enable performance counters (draw call count, frame timing) for debugging | ||
//#define GAME_PERFORMANCE_COUNTERS | ||
|
||
#include "../../menu/game/types.h" // includes e3v2/marlinui/game.h | ||
#include "../../lcdprint.h" | ||
#include "lcdprint_dwin.h" | ||
#include "marlinui_dwin.h" | ||
|
||
#if ENABLED(GAME_PERFORMANCE_COUNTERS) | ||
|
||
typedef struct { | ||
/** | ||
* Number of draw calls sent to the LCD | ||
*/ | ||
uint32_t draw_calls; | ||
|
||
/** | ||
* millis() value at the start of the current frame | ||
*/ | ||
millis_t frame_draw_millis; | ||
|
||
/** | ||
* millis() value at the end of the previous frame (in frame_start) | ||
* or time spend waiting for the next frame (in frame_end) | ||
*/ | ||
millis_t frame_wait_millis; | ||
} dwin_game_perf_t; | ||
|
||
static dwin_game_perf_t dwin_game_perf; | ||
|
||
#define COUNT_DRAW_CALLS(n) dwin_game_perf.draw_calls += n | ||
|
||
#else // !GAME_PERFORMANCE_COUNTERS | ||
|
||
#define COUNT_DRAW_CALLS(...) NOOP | ||
|
||
#endif // !GAME_PERFORMANCE_COUNTERS | ||
|
||
void MarlinGame::frame_start() { | ||
// Clear the screen before each frame | ||
//dwinFrameClear(CLEAR_COLOR); | ||
|
||
// Instead of using dwinFrameClear, fill the play area with the background color | ||
// This tends to be faster than clearing the whole screen | ||
const uint16_t fg = dwin_font.fg; | ||
dwin_font.fg = COLOR_BG_BLACK; | ||
draw_box(0, 0, GAME_WIDTH, GAME_HEIGHT); | ||
dwin_font.fg = fg; | ||
|
||
// Ensure the correct font is selected | ||
dwin_font.index = DWIN_FONT_MENU; | ||
|
||
#if ENABLED(GAME_PERFORMANCE_COUNTERS) | ||
// Reset draw call counters | ||
dwin_game_perf.draw_calls = 0; | ||
|
||
// Update timing information | ||
const millis_t now = millis(); | ||
dwin_game_perf.frame_draw_millis = now; | ||
dwin_game_perf.frame_wait_millis = now - dwin_game_perf.frame_wait_millis; | ||
#endif | ||
} | ||
|
||
void MarlinGame::frame_end() { | ||
#if ENABLED(GAME_PERFORMANCE_COUNTERS) | ||
const millis_t now = millis(); | ||
const millis_t frame_wait_millis = dwin_game_perf.frame_wait_millis; | ||
const millis_t frame_draw_millis = now - dwin_game_perf.frame_draw_millis; | ||
|
||
dwin_game_perf.frame_wait_millis = now; | ||
|
||
// Save previous font settings and set new ones | ||
const uint16_t fg = dwin_font.fg; | ||
const bool solid = dwin_font.solid; | ||
set_color(color::YELLOW); | ||
dwin_font.solid = true; | ||
|
||
// Draw performance counters information | ||
char perf_str[32]; | ||
sprintf_P( | ||
perf_str, | ||
PSTR("d%04lu w%04lu c%04lu"), | ||
frame_draw_millis, | ||
frame_wait_millis, | ||
dwin_game_perf.draw_calls | ||
); | ||
lcd_moveto_xy(0, 0); | ||
lcd_put_u8str(perf_str); | ||
|
||
// Restore previous font settings | ||
dwin_font.fg = fg; | ||
dwin_font.solid = solid; | ||
#endif // GAME_PERFORMANCE_COUNTERS | ||
} | ||
|
||
void MarlinGame::set_color(const color color) { | ||
switch (color) { | ||
default: | ||
case color::WHITE: dwin_font.fg = COLOR_WHITE; break; | ||
case color::BLACK: dwin_font.fg = COLOR_BG_BLACK; break; | ||
|
||
// https://rgbcolorpicker.com/565/table | ||
case color::RED: dwin_font.fg = RGB(0x1F, 0x00, 0x00); break; | ||
case color::GREEN: dwin_font.fg = RGB(0x00, 0x3F, 0x00); break; | ||
case color::BLUE: dwin_font.fg = RGB(0x00, 0x00, 0x1F); break; | ||
case color::YELLOW: dwin_font.fg = RGB(0x1F, 0x3F, 0x00); break; | ||
case color::CYAN: dwin_font.fg = RGB(0x00, 0x3F, 0x1F); break; | ||
case color::MAGENTA:dwin_font.fg = RGB(0x1F, 0x00, 0x1F); break; | ||
} | ||
} | ||
|
||
void MarlinGame::draw_hline(const game_dim_t x, const game_dim_t y, const game_dim_t w) { | ||
// Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them | ||
draw_box(x, y, w, 1); | ||
|
||
COUNT_DRAW_CALLS(1); | ||
} | ||
|
||
void MarlinGame::draw_vline(const game_dim_t x, const game_dim_t y, const game_dim_t h) { | ||
// Draw lines as boxes, since DWIN lines are always 1px wide but we want to scale them | ||
draw_box(x, y, 1, h); | ||
|
||
COUNT_DRAW_CALLS(1); | ||
} | ||
|
||
void MarlinGame::draw_frame(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { | ||
dwinDrawBox( | ||
0, // mode = frame | ||
dwin_font.fg, // color | ||
dwin_game::game_to_screen(x) + dwin_game::x_offset, | ||
dwin_game::game_to_screen(y) + dwin_game::y_offset, | ||
dwin_game::game_to_screen(w), | ||
dwin_game::game_to_screen(h) | ||
); | ||
|
||
COUNT_DRAW_CALLS(1); | ||
} | ||
|
||
void MarlinGame::draw_box(const game_dim_t x, const game_dim_t y, const game_dim_t w, const game_dim_t h) { | ||
dwinDrawBox( | ||
1, // mode = fill | ||
dwin_font.fg, // color | ||
dwin_game::game_to_screen(x) + dwin_game::x_offset, | ||
dwin_game::game_to_screen(y) + dwin_game::y_offset, | ||
dwin_game::game_to_screen(w), | ||
dwin_game::game_to_screen(h) | ||
); | ||
|
||
COUNT_DRAW_CALLS(1); | ||
} | ||
|
||
void MarlinGame::draw_pixel(const game_dim_t x, const game_dim_t y) { | ||
// Draw pixels using boxes. | ||
// While DWIN protocol supports drawing points with different sizes, the | ||
// 0x02 'draw point' command is slower per pixel than 0x05 'fill rectangle' | ||
// (0.4 us vs 0.14 us per pixel) | ||
draw_box(x, y, 1, 1); | ||
} | ||
|
||
void MarlinGame::draw_bitmap(const game_dim_t x, const game_dim_t y, const game_dim_t bytes_per_row, const game_dim_t rows, const pgm_bitmap_t bitmap) { | ||
// DWIN theorethically supports bitmaps since kernel 2.1, but most screens don't support it | ||
// (either because they use an older kernel version, or because they just (badly) emulate the DWIN protocol). | ||
// So instead, we have to fall back to drawing points manually. | ||
|
||
#if DISABLED(TJC_DISPLAY) | ||
|
||
// DWIN T5UI actually supports drawing multiple points in one go using the 0x02 'draw point' command, ever since kernel 1.2. | ||
// So we use that to draw the bitmap as a series of points, which is faster than drawing rectangles using draw_pixel. | ||
dwinDrawPointMap( | ||
dwin_font.fg, | ||
dwin_game::game_to_screen(1), | ||
dwin_game::game_to_screen(1), | ||
dwin_game::game_to_screen(x) + dwin_game::x_offset, | ||
dwin_game::game_to_screen(y) + dwin_game::y_offset, | ||
bytes_per_row, | ||
rows, | ||
bitmap | ||
); | ||
|
||
COUNT_DRAW_CALLS(1); | ||
|
||
#else // TJC_DISPLAY | ||
|
||
// TJC displays don't seem to support the 0x02 'draw point' command, so instead we have to draw the bitmap | ||
// as a series of rectangles using draw_pixel. | ||
// This will absolutely suck for performance, but it's the best we can do on these screens. | ||
for (game_dim_t row = 0; row < rows; row++) { | ||
for (game_dim_t col = 0; col < bytes_per_row; col++) { | ||
const uint8_t byte = bitmap[(row * bytes_per_row) + col]; | ||
for (uint8_t bit = 0; bit < 8; bit++) { | ||
// Assuming that the drawing area was cleared before drawing | ||
if (byte & (1 << bit)) { | ||
draw_pixel(x + (col * 8) + (7 - bit + 1), y + row); | ||
COUNT_DRAW_CALLS(1); | ||
} | ||
} | ||
} | ||
} | ||
|
||
#endif // TJC_DISPLAY | ||
} | ||
|
||
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, const char* str) { | ||
COUNT_DRAW_CALLS(1); | ||
|
||
lcd_moveto_xy( | ||
dwin_game::game_to_screen(x) + dwin_game::x_offset, | ||
dwin_game::game_to_screen(y) + dwin_game::y_offset | ||
); | ||
|
||
return lcd_put_u8str_max_P(str, PIXEL_LEN_NOLIMIT); | ||
} | ||
|
||
int MarlinGame::draw_string(const game_dim_t x, const game_dim_t y, FSTR_P const str) { | ||
return draw_string(x, y, FTOP(str)); | ||
} | ||
|
||
void MarlinGame::draw_int(const game_dim_t x, const game_dim_t y, const int value) { | ||
COUNT_DRAW_CALLS(1); | ||
|
||
lcd_moveto_xy( | ||
dwin_game::game_to_screen(x) + dwin_game::x_offset, | ||
dwin_game::game_to_screen(y) + dwin_game::y_offset | ||
); | ||
|
||
lcd_put_int(value); | ||
} | ||
|
||
#endif // IS_DWIN_MARLINUI && HAS_GAMES |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/** | ||
* Marlin 3D Printer Firmware | ||
* Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] | ||
* | ||
* Based on Sprinter and grbl. | ||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
#pragma once | ||
|
||
#include "../marlinui/marlinui_dwin.h" | ||
|
||
typedef uint8_t game_dim_t; | ||
typedef uint16_t screen_dim_t; | ||
typedef const uint8_t* pgm_bitmap_t; | ||
|
||
namespace dwin_game { | ||
/** | ||
* @brief Target the renderer at 128x64 pixels to match U8G screens | ||
*/ | ||
constexpr screen_dim_t TARGET_WIDTH = 128; | ||
constexpr screen_dim_t TARGET_HEIGHT = 64; | ||
|
||
constexpr int calculate_scale() { | ||
// Use whichever is smaller: the width or height scaling factor | ||
float scaling_factor = _MIN( | ||
static_cast<float>(DWIN_WIDTH) / static_cast<float>(TARGET_WIDTH), | ||
static_cast<float>(DWIN_HEIGHT) / static_cast<float>(TARGET_HEIGHT) | ||
); | ||
|
||
// Round DOWN to closest integer | ||
return static_cast<int>(scaling_factor); | ||
} | ||
|
||
/** | ||
* @brief Game render scale. | ||
*/ | ||
constexpr int scale = calculate_scale(); | ||
|
||
/** | ||
* @brief Scale a game dimension to screen dimensions | ||
*/ | ||
constexpr game_dim_t screen_to_game(const screen_dim_t x) { | ||
return x / scale; | ||
} | ||
|
||
/** | ||
* @brief Scale a screen dimension to game dimensions | ||
*/ | ||
constexpr screen_dim_t game_to_screen(const game_dim_t x) { | ||
return x * scale; | ||
} | ||
|
||
/** | ||
* @brief Offset of the game window on the screen. Applied after scaling. | ||
*/ | ||
constexpr screen_dim_t x_offset = (DWIN_WIDTH - game_to_screen(TARGET_WIDTH)) / 2; | ||
constexpr screen_dim_t y_offset = (DWIN_HEIGHT - game_to_screen(TARGET_HEIGHT)) / 2; | ||
|
||
static_assert(game_to_screen(TARGET_WIDTH) + (x_offset * 2) <= DWIN_WIDTH, "DWIN game renderer failed to auto-scale, is too wide"); | ||
static_assert(game_to_screen(TARGET_HEIGHT) + (y_offset * 2) <= DWIN_HEIGHT, "DWIN game renderer failed to auto-scale, is too high"); | ||
} // namespace dwin_game | ||
|
||
constexpr game_dim_t GAME_WIDTH = dwin_game::screen_to_game(DWIN_WIDTH - (dwin_game::x_offset * 2)); | ||
constexpr game_dim_t GAME_HEIGHT = dwin_game::screen_to_game(DWIN_HEIGHT - (dwin_game::y_offset * 2)); | ||
constexpr game_dim_t GAME_FONT_WIDTH = dwin_game::screen_to_game(MENU_FONT_WIDTH); | ||
constexpr game_dim_t GAME_FONT_ASCENT = dwin_game::screen_to_game(MENU_FONT_ASCENT); | ||
|
||
// DWIN screens don't page, so these macros are always true | ||
#define PAGE_OVER(ya) true | ||
#define PAGE_UNDER(yb) true | ||
#define PAGE_CONTAINS(ya, yb) true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters