ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mg_reader.h File Reference

Tap-driven pan/zoom viewer over a tiled manga page (ereader_manga). More...

#include <stddef.h>
#include <stdint.h>
#include "jof.h"
#include "ra8_err.h"
#include "ra8_tile_cache.h"
Include dependency graph for mg_reader.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  mg_tile_src_t
 Decode-on-miss context bound into the tile cache (DIP seam). More...
struct  mg_reader_cfg_t
 Everything mg_reader_init needs to bind a viewer to a page. More...
struct  mg_reader_t
 Viewer state: the page geometry plus the current viewport + zoom. More...

Enumerations

enum  mg_layout_t : uint16_t {
  k_mg_statusbar_h = 48U ,
  k_mg_pan_step = 256U ,
  k_mg_edge_band = 176U ,
  k_mg_minimap_w = 104U ,
  k_mg_minimap_h = 140U ,
  k_mg_minimap_pad = 14U ,
  k_mg_minimap_in = 2U
}
 Fixed chrome + navigation geometry, in panel/page pixels. More...
enum  mg_zoom_t : uint8_t {
  k_mg_zoom_full = 0U ,
  k_mg_zoom_fit = 1U
}
 The two zoom states cycled by a centre tap. More...
enum  mg_zone_t : uint8_t {
  k_mg_zone_none = 0U ,
  k_mg_zone_pan_up = 1U ,
  k_mg_zone_pan_down = 2U ,
  k_mg_zone_pan_left = 3U ,
  k_mg_zone_pan_right = 4U ,
  k_mg_zone_zoom = 5U
}
 The tap-zone a panel coordinate falls in (mg_zone_hit result). More...

Functions

ra8_err_t mg_reader_init (mg_reader_t *r, const mg_reader_cfg_t *cfg)
 Bind a viewer to a produced atlas and reset it to 1:1 top-left.
mg_zone_t mg_zone_hit (const mg_reader_t *r, int32_t x, int32_t y)
 Classify a panel coordinate into its tap-zone.
bool mg_reader_tap (mg_reader_t *r, int32_t x, int32_t y)
 Apply a tap: pan or toggle zoom, and report whether state changed.
bool mg_reader_toggle_zoom (mg_reader_t *r)
 Toggle the zoom between 1:1 and fit-page (SW-button entry point).
ra8_err_t mg_reader_render (mg_reader_t *r)
 Render the current viewport + chrome into the framebuffer.
ra8_err_t mg_reader_prefetch (mg_reader_t *r)
 Warm the tiles one step ahead of the last pan (predictive prefetch).
ra8_err_t mg_reader_status (const mg_reader_t *r, char *buf, uint32_t cap)
 Format the status-bar string ("MANGA 1:1 x=.. y=..").
uint32_t mg_fnv1a (const void *buf, uint32_t len)
 FNV-1a-32 over a byte buffer (framebuffer render hash for the banner).
ra8_err_t mg_tile_decode (void *ctx, const ra8_tile_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h)
 Tile-cache decode-on-miss callback: page one atlas tile into a cell.

Detailed Description

Tap-driven pan/zoom viewer over a tiled manga page (ereader_manga).

Tag
[Ring 6 / APP] {World: NS}

The presentation model for the ereader_manga demo: a viewport onto a page far larger than the 1024x600 panel, backed by a JOF tile atlas (jof) paged through a small fixed-budget tile cache (ra8_tile_cache). The reader owns no hardware – it draws into a caller-supplied RGB565 framebuffer through ra8_gfx and reads decoded tiles through the cache – so the identical render runs on the cross-built firmware, under ra8_emulator, and in the host unit test.

Navigation is discrete tap-zones (ra8_emulator's GT911 model has no gestures):

  • the four screen-edge bands pan the viewport one step in that direction;
  • a tap anywhere in the centre toggles the zoom between 1:1 (pan a page bigger than the screen) and fit-page (the whole page decimated to fit).

A tile is fetched, blitted, and released one at a time, so a viewport that spans more tiles than the cache has cells forces LRU eviction every frame – the streaming-larger-than-RAM property the tile cache exists for.

Since
0.1.0

Definition in file mg_reader.h.

Enumeration Type Documentation

◆ mg_layout_t

enum mg_layout_t : uint16_t

Fixed chrome + navigation geometry, in panel/page pixels.

The status band and minimap are panel-pixel metrics; the pan step is measured in page pixels (how far one edge tap slides the viewport); the edge band is the panel-pixel thickness of each pan tap-zone.

Since
0.1.0
Enumerator
k_mg_statusbar_h 

Top status-bar band height, panel px.

k_mg_pan_step 

Viewport slide per edge tap, page px.

k_mg_edge_band 

Edge pan tap-zone thickness, panel px.

k_mg_minimap_w 

Minimap overlay width, panel px.

k_mg_minimap_h 

Minimap overlay height, panel px.

k_mg_minimap_pad 

Minimap inset from the panel edge, px.

k_mg_minimap_in 

Minimap interior inset, px.

Definition at line 54 of file mg_reader.h.

◆ mg_zone_t

enum mg_zone_t : uint8_t

The tap-zone a panel coordinate falls in (mg_zone_hit result).

Since
0.1.0
Enumerator
k_mg_zone_none 

Outside every actionable zone.

k_mg_zone_pan_up 

Top edge band: slide viewport up.

k_mg_zone_pan_down 

Bottom edge band: slide down.

k_mg_zone_pan_left 

Left edge band: slide left.

k_mg_zone_pan_right 

Right edge band: slide right.

k_mg_zone_zoom 

Centre: toggle 1:1 <-> fit-page.

Definition at line 81 of file mg_reader.h.

◆ mg_zoom_t

enum mg_zoom_t : uint8_t

The two zoom states cycled by a centre tap.

Since
0.1.0
Enumerator
k_mg_zoom_full 

1:1 – one page pixel per panel pixel; panned.

k_mg_zoom_fit 

Fit-page – whole page decimated to the panel.

Definition at line 70 of file mg_reader.h.

Function Documentation

◆ mg_fnv1a()

uint32_t mg_fnv1a ( const void * buf,
uint32_t len )
nodiscard

FNV-1a-32 over a byte buffer (framebuffer render hash for the banner).

Parameters
[in]bufBytes to hash.
[in]lenByte count.
Returns
uint32_t The FNV-1a-32 digest.
Return values
2166136261The offset basis, when len is 0 (empty digest).
Precondition
buf holds len readable bytes (or len is 0).
None.
Postcondition
No state is mutated.
The digest is deterministic across host / ra8_emulator / silicon.
Note
Thread-safe (pure).
Since
0.1.0

Definition at line 540 of file mg_reader.c.

References k_mg_fnv_offset, and k_mg_fnv_prime.

Referenced by mg_print_banner().

◆ mg_reader_init()

ra8_err_t mg_reader_init ( mg_reader_t * r,
const mg_reader_cfg_t * cfg )
nodiscard

Bind a viewer to a produced atlas and reset it to 1:1 top-left.

Parameters
[out]rReader state to populate.
[in]cfgFramebuffer + cache + parsed atlas geometry.
Returns
ra8_err_t Error code.
Return values
k_ra8_okReader ready; viewport at (0,0), zoom 1:1.
k_ra8_err_null_ptrr, cfg, or a required cfg field NULL.
k_ra8_err_invalid_sizecfg geometry is zero / smaller than the fb.
k_ra8_err_not_supportedcfg->info->bpp is not 1 (gray8); the blit path reads one byte per pixel, so a colour atlas is rejected rather than mis-rendered.
Precondition
cfg->info came from a successful jof_parse.
cfg->info->bpp == 1 (gray8); colour atlases are unsupported.
cfg->fb covers fb_w * fb_h RGB565 pixels.
Postcondition
On success the viewport is clamped inside the page.
On any error r is left unbound.
Note
Not thread-safe.
Since
0.1.0

Definition at line 619 of file mg_reader.c.

References k_ra8_ok, mg_reader_bind(), mg_reader_check_geometry(), and mg_reader_check_ptrs().

Referenced by main().

◆ mg_reader_prefetch()

ra8_err_t mg_reader_prefetch ( mg_reader_t * r)
nodiscard

Warm the tiles one step ahead of the last pan (predictive prefetch).

Called in the idle window after mg_reader_render presents a panned frame, so the next tiles the viewport will expose are decoded into the cache before the next pan needs them – the image counterpart of the chapter-text read-ahead (book_src_prefetch_chapter). Warms the lead tile row/column in r->last_pan through ra8_tile_cache_prefetch_pan, sizing the budget from the cache's spare capacity (capacity - currently-visible tiles) so a prefetch can never evict an on-screen tile. A no-op when the last action was not a moving pan (last_pan == k_ra8_tile_pan_none – the initial frame, a zoom toggle, a pan clamped at the page edge, or fit-page zoom where a pan is a no-op), or when the cache has no spare capacity. Transparent: warming changes only residency, so the next mg_reader_render is byte-identical.

Parameters
[in,out]rBound reader (its last_pan seeds the direction).
Returns
ra8_err_t Error code.
Return values
k_ra8_okPrefetch ran (possibly warming zero tiles).
k_ra8_err_null_ptrr or its cache was NULL.
k_ra8_err_*Propagated from ra8_tile_cache_prefetch_pan.
Precondition
r was populated by mg_reader_init.
The tile cache can decode the lead-edge tiles.
Postcondition
No on-screen tile resident after the last render is evicted.
r->fb and the viewport state are unchanged.
Note
Not thread-safe. Single-threaded read-ahead only.
See also
mg_reader_render()
Since
0.1.0

Definition at line 349 of file mg_reader.c.

References mg_reader_t::cache, mg_reader_t::image_id, k_mg_tag, k_ra8_ok, k_ra8_tile_pan_none, mg_reader_t::last_pan, mg_region(), mg_tiles_of_region(), RA8_CHECK_NULL_PTR, ra8_tile_cache_capacity(), ra8_tile_cache_prefetch_pan(), mg_reader_t::tile_cols, and mg_reader_t::tile_rows.

Referenced by mg_poll_touch().

◆ mg_reader_render()

ra8_err_t mg_reader_render ( mg_reader_t * r)
nodiscard

Render the current viewport + chrome into the framebuffer.

Clears the framebuffer, pages every tile overlapping the viewport through the cache (get/blit/put one at a time so a small cache evicts across the frame), packs gray8 to RGB565 with nearest- neighbour decimation at fit-page zoom, then draws the status bar and the minimap overlay.

Parameters
[in,out]rBound reader.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe framebuffer holds the current view.
k_ra8_err_null_ptrr or its framebuffer was NULL.
k_ra8_err_*Propagated from the tile cache / gfx.
Precondition
r was populated by mg_reader_init and ra8_gfx is bound to r->fb.
The tile cache can decode every covered tile.
Postcondition
On success r->fb holds the rendered screen.
Every tile pinned during the frame was released.
Note
Not thread-safe.
Since
0.1.0

Definition at line 332 of file mg_reader.c.

References mg_reader_t::fb, k_mg_col_letterbox, k_mg_tag, k_ra8_ok, mg_render_minimap(), mg_render_page(), mg_render_status(), RA8_CHECK_NULL_PTR, and ra8_gfx_clear().

Referenced by main(), and mg_poll_touch().

◆ mg_reader_status()

ra8_err_t mg_reader_status ( const mg_reader_t * r,
char * buf,
uint32_t cap )
nodiscard

Format the status-bar string ("MANGA 1:1 x=.. y=..").

Parameters
[in]rBound reader.
[out]bufDestination, NUL-terminated on return.
[in]capCapacity of buf (>= 1).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe status text was written.
k_ra8_err_null_ptrr or buf was NULL.
k_ra8_err_invalid_sizecap was 0.
Precondition
r was populated by mg_reader_init.
buf holds cap writable bytes.
Postcondition
buf is NUL-terminated within cap.
No reader state is mutated.
Note
Thread-safe for distinct buffers.
Since
0.1.0

Definition at line 522 of file mg_reader.c.

References k_mg_tag, k_mg_zoom_full, k_ra8_err_invalid_size, k_ra8_ok, mg_append_str(), mg_append_uint(), RA8_CHECK_NULL_PTR, mg_reader_t::view_x, mg_reader_t::view_y, and mg_reader_t::zoom.

Referenced by mg_render_status().

◆ mg_reader_tap()

bool mg_reader_tap ( mg_reader_t * r,
int32_t x,
int32_t y )
nodiscard

Apply a tap: pan or toggle zoom, and report whether state changed.

Maps (x,y) through mg_zone_hit, then mutates the viewport (an edge zone, clamped inside the page) or the zoom (the centre zone). A pan already at the page edge, or a tap on no zone, leaves the state unchanged and returns false so the caller can skip the redraw.

Parameters
[in,out]rBound reader.
[in]xTap X, panel pixels.
[in]yTap Y, panel pixels.
Returns
bool Whether the viewport or zoom changed.
Return values
trueState changed; the caller should re-render.
falseTap hit nothing actionable (no redraw needed).
Precondition
r was populated by mg_reader_init.
x and y are panel coordinates.
Postcondition
On true the viewport/zoom reflects the tap, clamped inside the page.
On false r is byte-for-byte unchanged.
Note
Not thread-safe.
Since
0.1.0

Definition at line 461 of file mg_reader.c.

References k_mg_pan_step, k_mg_zone_none, k_mg_zone_pan_down, k_mg_zone_pan_left, k_mg_zone_pan_right, k_mg_zone_pan_up, k_mg_zone_zoom, mg_pan(), mg_reader_toggle_zoom(), and mg_zone_hit().

Referenced by mg_poll_touch().

◆ mg_reader_toggle_zoom()

bool mg_reader_toggle_zoom ( mg_reader_t * r)
nodiscard

Toggle the zoom between 1:1 and fit-page (SW-button entry point).

Parameters
[in,out]rBound reader.
Returns
bool Whether the zoom was toggled.
Return values
trueThe zoom state flipped (the normal case).
falser was NULL (nothing toggled).
Precondition
r was populated by mg_reader_init.
None.
Postcondition
On true r->zoom is the other mg_zoom_t member.
The viewport is re-clamped for the new zoom.
Note
Not thread-safe.
Since
0.1.0

Definition at line 450 of file mg_reader.c.

References k_mg_zoom_fit, k_mg_zoom_full, k_ra8_tile_pan_none, mg_reader_t::last_pan, mg_clamp(), and mg_reader_t::zoom.

Referenced by mg_reader_tap().

◆ mg_tile_decode()

ra8_err_t mg_tile_decode ( void * ctx,
const ra8_tile_key_t * key,
uint8_t * cell,
uint32_t cell_bytes,
uint16_t * out_w,
uint16_t * out_h )
nodiscard

Tile-cache decode-on-miss callback: page one atlas tile into a cell.

Matches ra8_tile_decode_fn. Reads key->tile_x / tile_y and reads that tile out of the atlas through jof_read_tile (raw copy or deflate inflate) into cell, reporting the tile's clamped dimensions.

Parameters
[in]ctxA mg_tile_src_t* bound at cache init.
[in]keyThe tile to decode.
[out]cellDestination cell (cell_bytes writable).
[in]cell_bytesCell capacity in bytes.
[out]out_wDecoded tile width, pixels.
[out]out_hDecoded tile height, pixels.
Returns
ra8_err_t k_ra8_ok on success, or the read-tile error verbatim.
Return values
k_ra8_okTile decoded into cell.
k_ra8_err_null_ptrA required pointer was NULL.
k_ra8_err_*Propagated from jof_read_tile.
Precondition
ctx points at a live mg_tile_src_t.
cell holds cell_bytes writable bytes.
Postcondition
On success (*out_w) * (*out_h) gray8 bytes are valid in cell.
On any error cell content is unspecified.
Note
Not thread-safe (shares the read-tile scratch).
Since
0.1.0

Definition at line 633 of file mg_reader.c.

References mg_tile_src_t::info, jof_read_tile(), k_mg_tag, mg_tile_src_t::pread, mg_tile_src_t::pread_ctx, RA8_CHECK_NULL_PTR, mg_tile_src_t::scratch, mg_tile_src_t::scratch_cap, ra8_tile_key_t::tile_x, and ra8_tile_key_t::tile_y.

Referenced by mg_setup_cache().

◆ mg_zone_hit()

mg_zone_t mg_zone_hit ( const mg_reader_t * r,
int32_t x,
int32_t y )
nodiscard

Classify a panel coordinate into its tap-zone.

Pure hit-test with no side effects: the centre rectangle (inside all four edge bands, below the status bar) is the zoom zone; each edge band is its pan zone; the status bar and any gap map to k_mg_zone_none.

Parameters
[in]rBound reader (for the framebuffer extent).
[in]xTap X, panel pixels.
[in]yTap Y, panel pixels.
Returns
mg_zone_t The zone (x,y) falls in.
Return values
k_mg_zone_noneStatus bar / outside the content area.
k_mg_zone_pan_*An edge band.
k_mg_zone_zoomThe centre.
Precondition
r was populated by mg_reader_init.
x and y are panel coordinates.
Postcondition
No state is mutated.
The result is one mg_zone_t member.
Note
Thread-safe (pure over its inputs).
Since
0.1.0

Definition at line 417 of file mg_reader.c.

References mg_reader_t::fb_h, mg_reader_t::fb_w, k_mg_edge_band, k_mg_statusbar_h, k_mg_zone_none, k_mg_zone_pan_down, k_mg_zone_pan_left, k_mg_zone_pan_right, k_mg_zone_pan_up, and k_mg_zone_zoom.

Referenced by mg_reader_tap().