Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions docs/api_reference/core/engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ Creates a new engine instance with custom display, input, and audio configuratio
#include "audio/AudioConfig.h"

pixelroot32::graphics::DisplayConfig displayConfig;
displayConfig.width = 128;
displayConfig.height = 128;
displayConfig.logicalWidth = 128;
displayConfig.logicalHeight = 128;

pixelroot32::input::InputConfig inputConfig;
// Configure input pins...
Expand Down Expand Up @@ -278,29 +278,42 @@ void playMusic() {
}
```

## Optional: FPS overlay
## Optional: Debug Statistics Overlay

When the engine is built with the preprocessor define **`PIXELROOT32_ENABLE_FPS_DISPLAY`**, an on-screen FPS counter is drawn each frame.
When the engine is built with the preprocessor define **`PIXELROOT32_ENABLE_DEBUG_OVERLAY`**, an on-screen technical overlay is drawn each frame.

**Metrics Included:**

- **FPS**: Frames per second (Green).
- **RAM**: Used heap memory in KB (Cyan).
- **CPU**: Estimated processor load percentage (Yellow).

!!! note "Platform Differences & CPU Metric"
The **CPU Load** metric is an estimation based on the processing time vs. a 60 FPS target (16.6ms).

* **On ESP32**: This is a realistic representation of how much time the CPU is spending on engine logic within its power limits.
* **On Native (PC)**: This metric may frequently show **100%** or high values even if your PC is idle. This happens because the native loop is synchronized with the monitor's VSYNC (via SDL2), which often causes the frame time to exceed 16.6ms (e.g., 33ms for 30 FPS). This is a result of the operating system's scheduling and SDL's synchronization, not actual hardware saturation.

**Behavior:**

- A green text string `"FPS xxx"` is drawn in the top-right area (position from `Renderer::getWidth()` and a fixed Y offset).
- The value is derived from frame delta time (FPS = 1000 / deltaTime ms), clamped to 0–999.
- The overlay is drawn in the top-right area of the screen.
- It is rendered after the scene, making it fixed and independent of the camera.

**Performance:**

- The numeric value is recalculated and formatted only every **8 frames**; the cached string is drawn every frame to keep the overlay visible without extra per-frame cost (division and `snprintf` are done at most once every 8 frames).
- Metric values are recalculated and formatted only every **16 frames** (`DEBUG_UPDATE_INTERVAL`).
- Cached strings are drawn every frame to minimize per-frame cost (division and `snprintf`).

**How to enable:**

In `platformio.ini`, add to your environment's `build_flags`:

```ini
build_flags =
-D PIXELROOT32_ENABLE_FPS_DISPLAY
-D PIXELROOT32_ENABLE_DEBUG_OVERLAY
```

No code changes are required; the overlay is drawn automatically after the scene in `Engine::draw()`. The implementation uses the private method `drawFpsOverlay(Renderer& r)`, which is only compiled when the define is set.
Alternatively, you can enable it in `EngineConfig.h`. The implementation uses the private method `drawDebugOverlay(Renderer& r)`, which is only compiled when the define is set.

See also: [Performance Tuning - Profiling](../../manual/optimization/performance_tuning.md) and [Platforms and Drivers - Build flags](../../manual/optimization/platforms_and_drivers.md).

Expand All @@ -314,8 +327,8 @@ See also: [Performance Tuning - Profiling](../../manual/optimization/performance
void setup() {
// Configure display
pixelroot32::graphics::DisplayConfig displayConfig;
displayConfig.width = 128;
displayConfig.height = 128;
displayConfig.logicalWidth = 128;
displayConfig.logicalHeight = 128;
displayConfig.rotation = 0;

// Create engine
Expand Down
141 changes: 104 additions & 37 deletions docs/api_reference/graphics/display_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The type of display.

### int rotation

Display rotation in degrees.
Display rotation. Supports both index-based (0-3) and degree-based (0, 90, 180, 270) values.

**Type:** `int`

Expand All @@ -49,37 +49,68 @@ Display rotation in degrees.
**Default:** `0`

**Notes:**
- Common values: 0, 90, 180, 270
- Rotation is applied during initialization
- Some displays may not support all rotations
- `0`: Normal orientation (0°)
- `1` or `90`: Rotated 90 degrees clockwise
- `2` or `180`: Rotated 180 degrees
- `3` or `270`: Rotated 90 degrees counter-clockwise (270°)
- Rotation is applied during initialization.
- On ESP32, this affects both the hardware display orientation and the internal framebuffer.
- On Native (SDL2), this rotates the rendered texture before presenting it.

### uint16_t width
### uint16_t physicalWidth

Display width in pixels.
Physical hardware width of the display.

**Type:** `uint16_t`

**Access:** Read-write

**Default:** `240`
**Notes:**
- Defines the actual resolution of the display hardware.

### uint16_t physicalHeight

Physical hardware height of the display.

**Type:** `uint16_t`

**Access:** Read-write

**Notes:**
- Should match actual display width
- Used for viewport and camera calculations
- Defines the actual resolution of the display hardware.

### uint16_t height
### uint16_t logicalWidth

Display height in pixels.
Logical rendering width. This is the resolution the game "sees" and draws to.

**Type:** `uint16_t`

**Access:** Read-write

**Default:** `240`
**Notes:**
- If smaller than `physicalWidth`, the image will be scaled up.
- Used for clipping, camera, and UI calculations.
- Recommended values for ESP32: 160, 128, 96 (for 240 physical).

### uint16_t logicalHeight

Logical rendering height. This is the resolution the game "sees" and draws to.

**Type:** `uint16_t`

**Access:** Read-write

**Notes:**
- Should match actual display height
- Used for viewport and camera calculations
- If smaller than `physicalHeight`, the image will be scaled up.
- Used for clipping, camera, and UI calculations.

### uint16_t width() (Deprecated)

Alias for `logicalWidth`. Maintained for backward compatibility.

### uint16_t height() (Deprecated)

Alias for `logicalHeight`. Maintained for backward compatibility.

### int xOffset

Expand Down Expand Up @@ -121,19 +152,53 @@ Gets the underlying DrawSurface implementation.
- Provides access to low-level display driver
- Platform-specific implementation

## Resolution Helpers

### bool needsScaling() const

Checks if the logical resolution differs from the physical resolution.

**Returns:**
- `bool`: `true` if scaling is active.

### float getScaleX() const

Gets the horizontal scaling factor (`physicalWidth / logicalWidth`).

### float getScaleY() const

Gets the vertical scaling factor (`physicalHeight / logicalHeight`).

## Constructors

### DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)
### DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)

Constructs a DisplayConfig with specified parameters.
Extended constructor that allows defining separate physical and logical resolutions.

**Parameters:**
- `type` (`DisplayType`): The display type
- `rot` (int, optional): Rotation in degrees. Default: `0`
- `w` (uint16_t, optional): Width in pixels. Default: `240`
- `h` (uint16_t, optional): Height in pixels. Default: `240`
- `xOffset` (int, optional): X offset. Default: `0`
- `yOffset` (int, optional): Y offset. Default: `0`
- `type` (`DisplayType`): The display type.
- `rot` (int): Rotation (0-3 or degrees depending on implementation).
- `physW` (uint16_t): Physical hardware width.
- `physH` (uint16_t): Physical hardware height.
- `logW` (uint16_t): Logical rendering width (0 = same as physical).
- `logH` (uint16_t): Logical rendering height (0 = same as physical).
- `xOff` (int, optional): X alignment offset.
- `yOff` (int, optional): Y alignment offset.

**Example:**
```cpp
// 128x128 game logic scaled to 240x240 display
pixelroot32::graphics::DisplayConfig config(
pixelroot32::graphics::DisplayType::ST7789,
0, // rotation
240, 240, // physical
128, 128 // logical
);
```

### DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)

Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values.

**Notes:**
- Automatically creates the appropriate `DrawSurface` for the platform
Expand All @@ -151,16 +216,18 @@ pixelroot32::graphics::DisplayConfig config(
pixelroot32::graphics::DisplayConfig config(
pixelroot32::graphics::DisplayType::ST7735,
90, // rotation
128, // width
128 // height
128, // physical width
128, // physical height
128, // logical width
128 // logical height
);

// Native/SDL2 (no specific display type)
pixelroot32::graphics::DisplayConfig config(
pixelroot32::graphics::DisplayType::NONE,
0, // rotation
128, // width
128 // height
128, 128, // physical
128, 128 // logical
);
```

Expand All @@ -173,12 +240,12 @@ pixelroot32::graphics::DisplayConfig config(
#include "graphics/DisplayConfig.h"

void setup() {
// Configure ST7789 display (240x240)
// Configure ST7789 display (240x240 physical, 128x128 logical)
pixelroot32::graphics::DisplayConfig displayConfig(
pixelroot32::graphics::DisplayType::ST7789,
0, // rotation
240, // width
240 // height
240, 240, // physical
128, 128 // logical
);

// Use with Engine
Expand All @@ -197,8 +264,7 @@ void setup() {
pixelroot32::graphics::DisplayConfig displayConfig(
pixelroot32::graphics::DisplayType::ST7735,
0, // rotation
128, // width
128 // height
128, 128 // physical & logical
);
#endif
```
Expand All @@ -211,8 +277,7 @@ void setup() {
pixelroot32::graphics::DisplayConfig displayConfig(
pixelroot32::graphics::DisplayType::NONE,
0, // rotation
128, // width
128 // height
240, 240 // logical & physical
);
#endif
```
Expand All @@ -228,12 +293,14 @@ void setup() {

#ifdef PLATFORM_ESP32
displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;
displayConfig.width = 240;
displayConfig.height = 240;
displayConfig.physicalWidth = 240;
displayConfig.physicalHeight = 240;
displayConfig.logicalWidth = 160; // 160x160 logic
displayConfig.logicalHeight = 160;
#elif PLATFORM_NATIVE
displayConfig.type = pixelroot32::graphics::DisplayType::NONE;
displayConfig.width = 128;
displayConfig.height = 128;
displayConfig.logicalWidth = 128;
displayConfig.logicalHeight = 128;
#endif

displayConfig.rotation = 0;
Expand Down
Loading
Loading