ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mg_reader.c
Go to the documentation of this file.
1
19
20#include "mg_reader.h"
21
22#include <stddef.h>
23#include <stdint.h>
24
25#include "jof.h"
26#include "ra8_check.h"
27#include "ra8_err.h"
28#include "ra8_gfx.h"
29#include "ra8_gfx_font.h"
30#include "ra8_tile_cache.h"
31
33static const char k_mg_tag[] = "mg_reader";
34
40typedef enum : uint32_t {
41 k_mg_col_letterbox = 0x000000U,
42 k_mg_col_status_bg = 0x141420U,
43 k_mg_col_status_fg = 0xFFFFFFU,
44 k_mg_col_minimap_bg = 0x202830U,
45 k_mg_col_minimap_fg = 0x808890U,
48
54typedef enum : uint16_t {
61
67typedef enum : uint8_t {
71 k_mg_r_sh = 11U,
72 k_mg_g_sh = 5U,
73} mg_bits_t;
74
80typedef enum : uint32_t {
81 k_mg_fnv_offset = 2166136261U,
82 k_mg_fnv_prime = 16777619U,
83} mg_fnv_t;
84
98typedef enum : uint8_t {
101
102/* ===========================================================================
103 * Geometry helpers (pure; page-pixel <-> panel-pixel mapping)
104 * =========================================================================== */
105
107static int32_t mg_scale(const mg_reader_t* r)
108{
109 return (r->zoom == (uint8_t)k_mg_zoom_fit) ? (int32_t)r->fit_factor : 1;
110}
111
113static int32_t mg_content_h(const mg_reader_t* r)
114{
115 return r->fb_h - (int32_t)k_mg_statusbar_h;
116}
117
119static void mg_region(const mg_reader_t* r, int32_t* x0, int32_t* y0, int32_t* x1, int32_t* y1)
120{
121 const int32_t s = mg_scale(r);
122 *x0 = r->view_x;
123 *y0 = r->view_y;
124 int32_t xe = r->view_x + (r->fb_w * s);
125 int32_t ye = r->view_y + (mg_content_h(r) * s);
126 if (xe > (int32_t)r->page_w) {
127 xe = (int32_t)r->page_w;
128 }
129 if (ye > (int32_t)r->page_h) {
130 ye = (int32_t)r->page_h;
131 }
132 *x1 = xe;
133 *y1 = ye;
134}
135
137static void mg_offsets(const mg_reader_t* r, int32_t* ox, int32_t* oy)
138{
139 int32_t x0 = 0;
140 int32_t y0 = 0;
141 int32_t x1 = 0;
142 int32_t y1 = 0;
143 mg_region(r, &x0, &y0, &x1, &y1);
144 const int32_t s = mg_scale(r);
145 const int32_t disp_w = ((x1 - x0) + s - 1) / s;
146 const int32_t disp_h = ((y1 - y0) + s - 1) / s;
147 int32_t px = (r->fb_w - disp_w) / 2;
148 int32_t py = (mg_content_h(r) - disp_h) / 2;
149 *ox = (px > 0) ? px : 0;
150 *oy = (py > 0) ? py : 0;
151}
152
154static bool mg_map(const mg_reader_t* r,
155 int32_t s,
156 int32_t ox,
157 int32_t oy,
158 int32_t sx,
159 int32_t sy,
160 int32_t* dx,
161 int32_t* dy)
162{
163 const int32_t rx = sx - r->view_x;
164 const int32_t ry = sy - r->view_y;
165 if (((rx % s) != 0) || ((ry % s) != 0)) {
166 return false;
167 }
168 const int32_t px = ox + (rx / s);
169 const int32_t py = (int32_t)k_mg_statusbar_h + oy + (ry / s);
170 /* mg_blit_tile is the sole caller and clips sx/sy to mg_region before this
171 * mapping. mg_offsets is non-negative and the region is framebuffer-sized,
172 * so the resulting panel coordinate is inside the drawable content area. */
173 *dx = px;
174 *dy = py;
175 return true;
176}
177
179static uint16_t mg_g565(uint8_t g)
180{
181 const uint16_t r5 = (uint16_t)(g >> k_mg_r_drop);
182 const uint16_t g6 = (uint16_t)(g >> k_mg_g_drop);
183 const uint16_t b5 = (uint16_t)(g >> k_mg_r_drop);
184 return (uint16_t)(((uint16_t)(r5 << k_mg_r_sh)) | ((uint16_t)(g6 << k_mg_g_sh)) | b5);
185}
186
188static void mg_clamp(mg_reader_t* r)
189{
190 if (r->zoom == (uint8_t)k_mg_zoom_fit) {
191 r->view_x = 0;
192 r->view_y = 0;
193 return;
194 }
195 int32_t maxx = (int32_t)r->page_w - r->fb_w;
196 int32_t maxy = (int32_t)r->page_h - mg_content_h(r);
197 if (maxx < 0) {
198 maxx = 0;
199 }
200 if (maxy < 0) {
201 maxy = 0;
202 }
203 if (r->view_x < 0) {
204 r->view_x = 0;
205 } else if (r->view_x > maxx) {
206 r->view_x = maxx;
207 }
208 if (r->view_y < 0) {
209 r->view_y = 0;
210 } else if (r->view_y > maxy) {
211 r->view_y = maxy;
212 }
213}
214
215/* ===========================================================================
216 * Rendering
217 * =========================================================================== */
218
221 const ra8_tile_t* t,
222 uint16_t tx,
223 uint16_t ty,
224 int32_t s,
225 int32_t ox,
226 int32_t oy,
227 const int32_t reg[4])
228{
229 const int32_t px0 = (int32_t)tx * (int32_t)r->tile_w;
230 const int32_t py0 = (int32_t)ty * (int32_t)r->tile_h;
231 for (int32_t rr = 0; rr < (int32_t)t->height; ++rr) {
232 const int32_t sy = py0 + rr;
233 if ((sy < reg[1]) || (sy >= reg[3])) {
234 continue;
235 }
236 for (int32_t cc = 0; cc < (int32_t)t->width; ++cc) {
237 const int32_t sx = px0 + cc;
238 if ((sx < reg[0]) || (sx >= reg[2])) {
239 continue;
240 }
241 int32_t dx = 0;
242 int32_t dy = 0;
243 if (!mg_map(r, s, ox, oy, sx, sy, &dx, &dy)) {
244 continue;
245 }
246 const uint8_t g = t->pixels[(rr * (int32_t)t->width) + cc];
247 r->fb[(dy * r->fb_w) + dx] = mg_g565(g);
248 }
249 }
250}
251
253static void mg_tiles_of_region(const mg_reader_t* r, const int32_t reg[4], uint16_t out[4])
254{
255 out[0] = (uint16_t)(reg[0] / (int32_t)r->tile_w); /* tx0 */
256 out[1] = (uint16_t)(reg[1] / (int32_t)r->tile_h); /* ty0 */
257 out[2] = (uint16_t)((reg[2] - 1) / (int32_t)r->tile_w); /* tx1 */
258 out[3] = (uint16_t)((reg[3] - 1) / (int32_t)r->tile_h); /* ty1 */
259}
260
263{
264 int32_t reg[4] = {};
265 mg_region(r, &reg[0], &reg[1], &reg[2], &reg[3]);
266 int32_t s = mg_scale(r);
267 int32_t ox = 0;
268 int32_t oy = 0;
269 mg_offsets(r, &ox, &oy);
270 uint16_t tiles[4] = {};
271 mg_tiles_of_region(r, reg, tiles);
272 for (uint16_t ty = tiles[1]; ty <= tiles[3]; ++ty) {
273 for (uint16_t tx = tiles[0]; tx <= tiles[2]; ++tx) {
274 ra8_tile_key_t key = {.image_id = r->image_id, .tile_x = tx, .tile_y = ty, .zoom = 0U};
275 ra8_tile_t tile = {};
276 const ra8_err_t e = ra8_tile_cache_get(r->cache, &key, &tile);
277 if (e != k_ra8_ok) {
278 return e;
279 }
280 mg_blit_tile(r, &tile, tx, ty, s, ox, oy, reg);
281 const ra8_err_t p = ra8_tile_cache_put(r->cache, tile.pixels);
282 if (p != k_ra8_ok) {
283 return p;
284 }
285 }
286 }
287 return k_ra8_ok;
288}
289
292{
293 (void)ra8_gfx_rect(0, 0, r->fb_w, (int32_t)k_mg_statusbar_h, (uint32_t)k_mg_col_status_bg, true);
294 char line[k_mg_status_cap] = {};
295 (void)mg_reader_status(r, line, (uint32_t)k_mg_status_cap);
296 const int32_t ty = ((int32_t)k_mg_statusbar_h - (int32_t)k_mg_glyph_h) / 2;
297 return ra8_gfx_text_out((int32_t)k_mg_status_text_x,
298 ty,
299 line,
301 (uint32_t)k_mg_col_status_fg,
302 (uint32_t)k_mg_col_status_bg);
303}
304
307{
308 const int32_t mw = (int32_t)k_mg_minimap_w;
309 const int32_t mh = (int32_t)k_mg_minimap_h;
310 const int32_t mx = r->fb_w - mw - (int32_t)k_mg_minimap_pad;
311 const int32_t my = r->fb_h - mh - (int32_t)k_mg_minimap_pad;
312 (void)ra8_gfx_rect(mx, my, mw, mh, (uint32_t)k_mg_col_minimap_bg, true);
313 (void)ra8_gfx_rect(mx, my, mw, mh, (uint32_t)k_mg_col_minimap_fg, false);
314 const int32_t inx = mx + (int32_t)k_mg_minimap_in;
315 const int32_t iny = my + (int32_t)k_mg_minimap_in;
316 const int32_t inw = mw - (2 * (int32_t)k_mg_minimap_in);
317 const int32_t inh = mh - (2 * (int32_t)k_mg_minimap_in);
318 int32_t reg[4] = {};
319 mg_region(r, &reg[0], &reg[1], &reg[2], &reg[3]);
320 const int32_t vx = inx + ((reg[0] * inw) / (int32_t)r->page_w);
321 const int32_t vy = iny + ((reg[1] * inh) / (int32_t)r->page_h);
322 int32_t vw = ((reg[2] - reg[0]) * inw) / (int32_t)r->page_w;
323 int32_t vh = ((reg[3] - reg[1]) * inh) / (int32_t)r->page_h;
324 (void)ra8_gfx_rect(vx,
325 vy,
326 (vw > 1) ? vw : 1,
327 (vh > 1) ? vh : 1,
328 (uint32_t)k_mg_col_minimap_view,
329 false);
330}
331
333{
334 RA8_CHECK_NULL_PTR(r, k_mg_tag, "reader");
335 RA8_CHECK_NULL_PTR(r->fb, k_mg_tag, "fb");
336 (void)ra8_gfx_clear((uint32_t)k_mg_col_letterbox);
337 const ra8_err_t e = mg_render_page(r);
338 if (e != k_ra8_ok) {
339 return e;
340 }
341 const ra8_err_t s = mg_render_status(r);
342 if (s != k_ra8_ok) {
343 return s;
344 }
346 return k_ra8_ok;
347}
348
350{
351 RA8_CHECK_NULL_PTR(r, k_mg_tag, "reader");
352 RA8_CHECK_NULL_PTR(r->cache, k_mg_tag, "cache");
354 /* Last action was not a moving pan (initial frame, zoom toggle, or a pan
355 * clamped at the page edge): nothing ahead of the viewport to warm. A pan is
356 * a no-op at fit-zoom, so this also covers the whole-page-shown case. */
357 return k_ra8_ok;
358 }
359 int32_t reg[4] = {};
360 mg_region(r, &reg[0], &reg[1], &reg[2], &reg[3]);
361 uint16_t tiles[4] = {};
362 mg_tiles_of_region(r, reg, tiles);
363 /* Budget the prefetch to the cache's spare cells (capacity minus the tiles the
364 * current frame occupies) so warming can never evict an on-screen tile. */
365 const uint32_t frame =
366 ((uint32_t)(tiles[2] - tiles[0]) + 1U) * ((uint32_t)(tiles[3] - tiles[1]) + 1U);
367 const uint32_t cap = ra8_tile_cache_capacity(r->cache);
368 const uint32_t spare = (cap > frame) ? (cap - frame) : 0U;
369 const uint16_t budget = (spare > (uint32_t)UINT16_MAX) ? (uint16_t)UINT16_MAX : (uint16_t)spare;
370 const ra8_tile_prefetch_req_t req = {
371 .image_id = r->image_id,
372 .view = {.tx0 = tiles[0], .ty0 = tiles[1], .tx1 = tiles[2], .ty1 = tiles[3]},
373 .tile_cols = r->tile_cols,
374 .tile_rows = r->tile_rows,
375 .zoom = 0U,
376 .max_tiles = budget,
377 .dir = r->last_pan,
378 };
379 return ra8_tile_cache_prefetch_pan(r->cache, &req, nullptr);
380}
381
382/* ===========================================================================
383 * Navigation
384 * =========================================================================== */
385
387static ra8_tile_pan_dir_t mg_pan_dir(int32_t dx, int32_t dy)
388{
389 if (dx > 0) {
391 }
392 if (dx < 0) {
393 return k_ra8_tile_pan_left;
394 }
395 if (dy > 0) {
396 return k_ra8_tile_pan_down;
397 }
398 return k_ra8_tile_pan_up; /* dy < 0 */
399}
400
402static bool mg_pan(mg_reader_t* r, int32_t dx, int32_t dy)
403{
404 if (r->zoom == (uint8_t)k_mg_zoom_fit) {
405 return false; /* the whole page is shown -- nothing to pan */
406 }
407 const int32_t ox = r->view_x;
408 const int32_t oy = r->view_y;
409 r->view_x += dx;
410 r->view_y += dy;
411 mg_clamp(r);
412 const bool moved = (r->view_x != ox) || (r->view_y != oy);
414 return moved;
415}
416
417mg_zone_t mg_zone_hit(const mg_reader_t* r, int32_t x, int32_t y)
418{
419 if (r == nullptr) {
420 return k_mg_zone_none;
421 }
422 if (x < 0) {
423 return k_mg_zone_none;
424 }
425 if (x >= r->fb_w) {
426 return k_mg_zone_none;
427 }
428 if (y < (int32_t)k_mg_statusbar_h) {
429 return k_mg_zone_none; /* status bar */
430 }
431 if (y >= r->fb_h) {
432 return k_mg_zone_none;
433 }
434 const int32_t band = (int32_t)k_mg_edge_band;
435 if (y < ((int32_t)k_mg_statusbar_h + band)) {
436 return k_mg_zone_pan_up;
437 }
438 if (y >= (r->fb_h - band)) {
439 return k_mg_zone_pan_down;
440 }
441 if (x < band) {
442 return k_mg_zone_pan_left;
443 }
444 if (x >= (r->fb_w - band)) {
445 return k_mg_zone_pan_right;
446 }
447 return k_mg_zone_zoom;
448}
449
451{
452 if (r == nullptr) {
453 return false;
454 }
455 r->zoom = (r->zoom == (uint8_t)k_mg_zoom_full) ? (uint8_t)k_mg_zoom_fit : (uint8_t)k_mg_zoom_full;
456 mg_clamp(r);
457 r->last_pan = (ra8_tile_pan_dir_t)k_ra8_tile_pan_none; /* a zoom is not a pan */
458 return true;
459}
460
461bool mg_reader_tap(mg_reader_t* r, int32_t x, int32_t y)
462{
463 if (r == nullptr) {
464 return false;
465 }
466 switch (mg_zone_hit(r, x, y)) {
467 case k_mg_zone_zoom:
468 return mg_reader_toggle_zoom(r);
469 case k_mg_zone_pan_up:
470 return mg_pan(r, 0, -(int32_t)k_mg_pan_step);
472 return mg_pan(r, 0, (int32_t)k_mg_pan_step);
474 return mg_pan(r, -(int32_t)k_mg_pan_step, 0);
476 return mg_pan(r, (int32_t)k_mg_pan_step, 0);
477 case k_mg_zone_none:
478 default:
479 return false;
480 }
481}
482
483/* ===========================================================================
484 * Status text + hashing + init + tile decode
485 * =========================================================================== */
486
488static uint32_t mg_append_uint(char* buf, uint32_t cap, uint32_t pos, int32_t val)
489{
490 char tmp[k_mg_dec_max] = {};
491 uint32_t n = 0U;
492 uint32_t v = (val < 0) ? 0U : (uint32_t)val;
493 if (v == 0U) {
494 tmp[n] = '0';
495 n++;
496 }
497 static_assert(k_mg_dec_max >= k_mg_i32_dec_digits, "signed 32-bit decimal text must fit");
498 while (v > 0U) {
499 tmp[n] = (char)('0' + (v % (uint32_t)k_mg_dec_ten));
500 n++;
501 v /= (uint32_t)k_mg_dec_ten;
502 }
503 for (uint32_t i = 0U; (i < n) && (pos < (cap - 1U)); ++i) {
504 buf[pos] = tmp[n - 1U - i];
505 pos++;
506 }
507 buf[pos] = '\0';
508 return pos;
509}
510
512static uint32_t mg_append_str(char* buf, uint32_t cap, uint32_t pos, const char* s, uint32_t length)
513{
514 for (uint32_t i = 0U; (i < length) && (pos < (cap - 1U)); ++i) {
515 buf[pos] = s[i];
516 pos++;
517 }
518 buf[pos] = '\0';
519 return pos;
520}
521
522ra8_err_t mg_reader_status(const mg_reader_t* r, char* buf, uint32_t cap)
523{
524 RA8_CHECK_NULL_PTR(r, k_mg_tag, "reader");
525 RA8_CHECK_NULL_PTR(buf, k_mg_tag, "buf");
526 if (cap == 0U) {
528 }
529 uint32_t pos = 0U;
530 pos = mg_append_str(buf, cap, pos, "MANGA ", sizeof("MANGA ") - 1U);
531 const char* zoom = (r->zoom == (uint8_t)k_mg_zoom_full) ? "1:1 x=" : "FIT x=";
532 static_assert(sizeof("1:1 x=") == sizeof("FIT x="), "zoom labels must have equal extents");
533 pos = mg_append_str(buf, cap, pos, zoom, sizeof("1:1 x=") - 1U);
534 pos = mg_append_uint(buf, cap, pos, r->view_x);
535 pos = mg_append_str(buf, cap, pos, " y=", sizeof(" y=") - 1U);
536 (void)mg_append_uint(buf, cap, pos, r->view_y);
537 return k_ra8_ok;
538}
539
540uint32_t mg_fnv1a(const void* buf, uint32_t len)
541{
542 const uint8_t* p = (const uint8_t*)buf;
543 if (p == nullptr) {
544 return (uint32_t)k_mg_fnv_offset;
545 }
546 uint32_t hsh = (uint32_t)k_mg_fnv_offset;
547 for (uint32_t i = 0U; i < len; ++i) {
548 hsh = (hsh ^ (uint32_t)p[i]) * (uint32_t)k_mg_fnv_prime;
549 }
550 return hsh;
551}
552
554static uint8_t mg_fit_factor(const mg_reader_t* r)
555{
556 const int32_t cw = r->fb_w;
557 const int32_t ch = mg_content_h(r);
558 const int32_t fx = ((int32_t)r->page_w + cw - 1) / cw;
559 const int32_t fy = ((int32_t)r->page_h + ch - 1) / ch;
560 int32_t f = (fx > fy) ? fx : fy;
561 if (f < 1) {
562 f = 1;
563 }
564 return (uint8_t)f;
565}
566
568static void mg_reader_bind(mg_reader_t* r, const mg_reader_cfg_t* cfg)
569{
570 *r = (mg_reader_t){.fb = cfg->fb,
571 .fb_w = cfg->fb_w,
572 .fb_h = cfg->fb_h,
573 .cache = cfg->cache,
574 .image_id = cfg->image_id,
575 .page_w = cfg->info->width,
576 .page_h = cfg->info->height,
577 .tile_w = cfg->info->tile_w,
578 .tile_h = cfg->info->tile_h,
579 .tile_cols = cfg->info->tile_cols,
580 .tile_rows = cfg->info->tile_rows,
581 .view_x = 0,
582 .view_y = 0,
583 .zoom = (uint8_t)k_mg_zoom_full,
584 .last_pan = k_ra8_tile_pan_none};
586 mg_clamp(r);
587}
588
591{
592 RA8_CHECK_NULL_PTR(r, k_mg_tag, "reader");
593 RA8_CHECK_NULL_PTR(cfg, k_mg_tag, "cfg");
594 RA8_CHECK_NULL_PTR(cfg->fb, k_mg_tag, "fb");
595 RA8_CHECK_NULL_PTR(cfg->cache, k_mg_tag, "cache");
596 RA8_CHECK_NULL_PTR(cfg->info, k_mg_tag, "info");
597 return k_ra8_ok;
598}
599
602{
603 if ((cfg->fb_w <= 0) || (cfg->fb_h <= (int32_t)k_mg_statusbar_h)) {
605 }
606 if ((cfg->info->width == 0U) || (cfg->info->height == 0U) || (cfg->info->tile_w == 0U) ||
607 (cfg->info->tile_h == 0U)) {
609 }
610 /* The blit path is gray8-only; a colour atlas (bpp 3/4) would be mis-read one
611 * byte per pixel and rendered as garbage. Fail closed instead (#339). */
612 if (cfg->info->bpp != (uint8_t)k_mg_gray8_bpp) {
613 ra8_log_error(k_mg_tag, "JOF atlas bpp unsupported: reader is gray8-only");
615 }
616 return k_ra8_ok;
617}
618
620{
621 const ra8_err_t pc = mg_reader_check_ptrs(r, cfg);
622 if (pc != k_ra8_ok) {
623 return pc;
624 }
625 const ra8_err_t gc = mg_reader_check_geometry(cfg);
626 if (gc != k_ra8_ok) {
627 return gc;
628 }
629 mg_reader_bind(r, cfg);
630 return k_ra8_ok;
631}
632
634 const ra8_tile_key_t* key,
635 uint8_t* cell,
636 uint32_t cell_bytes,
637 uint16_t* out_w,
638 uint16_t* out_h)
639{
640 RA8_CHECK_NULL_PTR(ctx, k_mg_tag, "src");
641 RA8_CHECK_NULL_PTR(key, k_mg_tag, "key");
642 const mg_tile_src_t* src = (const mg_tile_src_t*)ctx;
643 return jof_read_tile(src->pread,
644 src->pread_ctx,
645 src->info,
646 key->tile_x,
647 key->tile_y,
648 src->scratch,
649 src->scratch_cap,
650 cell,
651 cell_bytes,
652 out_w,
653 out_h);
654}
@ k_mg_dec_ten
Decimal radix / hex split.
Definition main.c:106
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
ra8_err_t jof_read_tile(jof_pread_fn pread, void *pread_ctx, const jof_info_t *info, uint16_t tile_x, uint16_t tile_y, uint8_t *scratch, uint32_t scratch_cap, uint8_t *out_px, uint32_t out_cap, uint16_t *out_w, uint16_t *out_h)
Read + decode one tile into caller pixels, in bounded RAM.
Definition jof.c:637
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.
Definition mg_reader.c:461
static const char k_mg_tag[]
Log tag for the reader's null-pointer guards.
Definition mg_reader.c:33
mg_pixfmt_t
The single JOF pixel format the reader can blit.
Definition mg_reader.c:98
@ k_mg_gray8_bpp
The only bytes-per-pixel the reader supports.
Definition mg_reader.c:99
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.
Definition mg_reader.c:633
mg_metric_t
Text / formatting metrics.
Definition mg_reader.c:54
@ k_mg_status_cap
Status-string scratch capacity.
Definition mg_reader.c:55
@ k_mg_glyph_h
ra8_gfx_font_8x16 glyph height.
Definition mg_reader.c:57
@ k_mg_i32_dec_digits
Maximum non-negative int32_t digits.
Definition mg_reader.c:59
@ k_mg_status_text_x
Status text left inset, panel px.
Definition mg_reader.c:56
@ k_mg_dec_max
Decimal digit scratch length.
Definition mg_reader.c:58
static uint32_t mg_append_uint(char *buf, uint32_t cap, uint32_t pos, int32_t val)
Append an unsigned decimal (from a signed val, clamped >= 0).
Definition mg_reader.c:488
static void mg_region(const mg_reader_t *r, int32_t *x0, int32_t *y0, int32_t *x1, int32_t *y1)
Source page rectangle currently shown, clamped to the page.
Definition mg_reader.c:119
static void mg_tiles_of_region(const mg_reader_t *r, const int32_t reg[4], uint16_t out[4])
Inclusive tile rect {tx0,ty0,tx1,ty1} covering a page region.
Definition mg_reader.c:253
static int32_t mg_content_h(const mg_reader_t *r)
Content-area height below the status bar, panel px.
Definition mg_reader.c:113
static ra8_err_t mg_reader_check_ptrs(const mg_reader_t *r, const mg_reader_cfg_t *cfg)
Null-guard the init inputs (5 preconditions, NASA Rule 5).
Definition mg_reader.c:590
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=..").
Definition mg_reader.c:522
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.
Definition mg_reader.c:417
uint32_t mg_fnv1a(const void *buf, uint32_t len)
FNV-1a-32 over a byte buffer (framebuffer render hash for the banner).
Definition mg_reader.c:540
static uint16_t mg_g565(uint8_t g)
Pack a gray8 sample into an RGB565 pixel.
Definition mg_reader.c:179
ra8_err_t mg_reader_prefetch(mg_reader_t *r)
Warm the tiles one step ahead of the last pan (predictive prefetch).
Definition mg_reader.c:349
ra8_err_t mg_reader_render(mg_reader_t *r)
Render the current viewport + chrome into the framebuffer.
Definition mg_reader.c:332
static ra8_err_t mg_render_page(mg_reader_t *r)
Page every tile overlapping the viewport through the cache and blit.
Definition mg_reader.c:262
static uint8_t mg_fit_factor(const mg_reader_t *r)
Smallest integer decimation that fits the page in the content area.
Definition mg_reader.c:554
static void mg_blit_tile(mg_reader_t *r, const ra8_tile_t *t, uint16_t tx, uint16_t ty, int32_t s, int32_t ox, int32_t oy, const int32_t reg[4])
Blit one pinned gray8 tile's viewport overlap into the framebuffer.
Definition mg_reader.c:220
mg_bits_t
gray8 -> RGB565 field shifts and the decimal radix.
Definition mg_reader.c:67
@ k_mg_r_drop
gray8 -> 5-bit field shift.
Definition mg_reader.c:69
@ k_mg_r_sh
RGB565 red field shift.
Definition mg_reader.c:71
@ k_mg_g_drop
gray8 -> 6-bit field shift.
Definition mg_reader.c:70
@ k_mg_g_sh
RGB565 green field shift.
Definition mg_reader.c:72
static void mg_offsets(const mg_reader_t *r, int32_t *ox, int32_t *oy)
Panel-pixel offset that centres the shown region in the content area.
Definition mg_reader.c:137
static void mg_clamp(mg_reader_t *r)
Viewport-clamp the reader for the active zoom (fit pins to 0,0).
Definition mg_reader.c:188
static ra8_err_t mg_reader_check_geometry(const mg_reader_cfg_t *cfg)
Validate framebuffer + atlas geometry; reject non-gray8 atlases (#339).
Definition mg_reader.c:601
static void mg_reader_bind(mg_reader_t *r, const mg_reader_cfg_t *cfg)
Populate reader state from an already-validated config (no checks).
Definition mg_reader.c:568
static int32_t mg_scale(const mg_reader_t *r)
Decimation factor for the active zoom (1 at 1:1, fit_factor at fit).
Definition mg_reader.c:107
static ra8_err_t mg_render_status(mg_reader_t *r)
Draw the top status bar (background band + the status string).
Definition mg_reader.c:291
static void mg_render_minimap(mg_reader_t *r)
Draw the bottom-right minimap: the page bounds + the viewport rect.
Definition mg_reader.c:306
mg_fnv_t
FNV-1a-32 constants.
Definition mg_reader.c:80
@ k_mg_fnv_prime
FNV-1a-32 prime.
Definition mg_reader.c:82
@ k_mg_fnv_offset
FNV-1a-32 offset basis.
Definition mg_reader.c:81
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.
Definition mg_reader.c:619
static bool mg_map(const mg_reader_t *r, int32_t s, int32_t ox, int32_t oy, int32_t sx, int32_t sy, int32_t *dx, int32_t *dy)
Map one caller-clipped page pixel to the panel; false if off-grid.
Definition mg_reader.c:154
mg_color_t
Chrome palette (0x00RRGGBB; ra8_gfx packs to RGB565).
Definition mg_reader.c:40
@ k_mg_col_minimap_bg
Minimap page area.
Definition mg_reader.c:44
@ k_mg_col_status_bg
Status-bar background.
Definition mg_reader.c:42
@ k_mg_col_minimap_view
Minimap current-viewport rect.
Definition mg_reader.c:46
@ k_mg_col_status_fg
Status-bar text.
Definition mg_reader.c:43
@ k_mg_col_letterbox
Framebuffer clear (page margins).
Definition mg_reader.c:41
@ k_mg_col_minimap_fg
Minimap frame.
Definition mg_reader.c:45
static uint32_t mg_append_str(char *buf, uint32_t cap, uint32_t pos, const char *s, uint32_t length)
Append an exact immutable fragment, bounded by cap.
Definition mg_reader.c:512
static bool mg_pan(mg_reader_t *r, int32_t dx, int32_t dy)
Slide the viewport by (dx,dy) page px; false if pinned / at fit.
Definition mg_reader.c:402
bool mg_reader_toggle_zoom(mg_reader_t *r)
Toggle the zoom between 1:1 and fit-page (SW-button entry point).
Definition mg_reader.c:450
static ra8_tile_pan_dir_t mg_pan_dir(int32_t dx, int32_t dy)
Pan direction of a (dx,dy) step (exactly one axis is non-zero).
Definition mg_reader.c:387
Tap-driven pan/zoom viewer over a tiled manga page (ereader_manga).
mg_zone_t
The tap-zone a panel coordinate falls in (mg_zone_hit result).
Definition mg_reader.h:81
@ k_mg_zone_pan_up
Top edge band: slide viewport up.
Definition mg_reader.h:83
@ k_mg_zone_zoom
Centre: toggle 1:1 <-> fit-page.
Definition mg_reader.h:87
@ k_mg_zone_pan_left
Left edge band: slide left.
Definition mg_reader.h:85
@ k_mg_zone_pan_right
Right edge band: slide right.
Definition mg_reader.h:86
@ k_mg_zone_none
Outside every actionable zone.
Definition mg_reader.h:82
@ k_mg_zone_pan_down
Bottom edge band: slide down.
Definition mg_reader.h:84
@ k_mg_minimap_h
Minimap overlay height, panel px.
Definition mg_reader.h:59
@ k_mg_edge_band
Edge pan tap-zone thickness, panel px.
Definition mg_reader.h:57
@ k_mg_minimap_w
Minimap overlay width, panel px.
Definition mg_reader.h:58
@ k_mg_pan_step
Viewport slide per edge tap, page px.
Definition mg_reader.h:56
@ k_mg_statusbar_h
Top status-bar band height, panel px.
Definition mg_reader.h:55
@ k_mg_minimap_in
Minimap interior inset, px.
Definition mg_reader.h:61
@ k_mg_minimap_pad
Minimap inset from the panel edge, px.
Definition mg_reader.h:60
@ k_mg_zoom_fit
Fit-page – whole page decimated to the panel.
Definition mg_reader.h:72
@ k_mg_zoom_full
1:1 – one page pixel per panel pixel; panned.
Definition mg_reader.h:71
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Software 2D graphics primitives layered on top of a caller-ownedframebuffer (DRW / D/AVE 2D / GLCDC r...
ra8_err_t ra8_gfx_clear(uint32_t color)
Fill the bound framebuffer's clip region with a single colour.
ra8_err_t ra8_gfx_text_out(int32_t x, int32_t y, const char *str, const ra8_gfx_font_t *font, uint32_t fg_color, uint32_t bg_color)
Render a NUL-terminated ASCII string.
ra8_err_t ra8_gfx_rect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color, bool filled)
Draw an axis-aligned rectangle.
Bitmap font descriptor + bundled font handles for ra8_gfx.
const ra8_gfx_font_t ra8_gfx_font_8x16
Bundled 8x16 IBM PC VGA bitmap font, ASCII 0x20..0x7E.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147).
ra8_err_t ra8_tile_cache_get(ra8_tile_cache_t *tc, const ra8_tile_key_t *key, ra8_tile_t *out_tile)
Get (and pin) the decoded tile for key.
ra8_err_t ra8_tile_cache_prefetch_pan(ra8_tile_cache_t *tc, const ra8_tile_prefetch_req_t *req, uint16_t *out_warmed)
Predictively warm the tiles one step ahead of a panning viewport.
ra8_err_t ra8_tile_cache_put(ra8_tile_cache_t *tc, const uint8_t *pixels)
Release one pin on a tile previously returned by ra8_tile_cache_get.
uint32_t ra8_tile_cache_capacity(const ra8_tile_cache_t *tc)
Report the number of cells the cache can hold.
ra8_tile_pan_dir_t
Direction of viewport travel, for predictive pan prefetch.
@ k_ra8_tile_pan_none
No travel: prefetch is a no-op.
@ k_ra8_tile_pan_up
Warm the row above the viewport.
@ k_ra8_tile_pan_down
Warm the row below the viewport.
@ k_ra8_tile_pan_left
Warm the column left of the viewport.
@ k_ra8_tile_pan_right
Warm the column right of the viewport.
uint8_t bpp
Bytes per pixel (1, 3 or 4).
Definition jof.h:215
uint16_t tile_w
Tile width, pixels.
Definition jof.h:211
uint16_t width
Image width, pixels.
Definition jof.h:209
uint16_t tile_rows
Ceil(height / tile_h) tile rows.
Definition jof.h:214
uint16_t tile_h
Tile height, pixels.
Definition jof.h:212
uint16_t height
Image height, pixels.
Definition jof.h:210
uint16_t tile_cols
Ceil(width / tile_w) tile columns.
Definition jof.h:213
Everything mg_reader_init needs to bind a viewer to a page.
Definition mg_reader.h:115
uint16_t * fb
RGB565 framebuffer (panel).
Definition mg_reader.h:116
const jof_info_t * info
Parsed atlas geometry.
Definition mg_reader.h:120
ra8_tile_cache_t * cache
Tile cache over the atlas.
Definition mg_reader.h:119
int32_t fb_h
Framebuffer height, pixels.
Definition mg_reader.h:118
uint32_t image_id
Tile-cache key image id.
Definition mg_reader.h:121
int32_t fb_w
Framebuffer width, pixels.
Definition mg_reader.h:117
Viewer state: the page geometry plus the current viewport + zoom.
Definition mg_reader.h:133
int32_t view_x
Viewport left in page px (1:1 anchor).
Definition mg_reader.h:145
int32_t view_y
Viewport top in page px (1:1 anchor).
Definition mg_reader.h:146
uint32_t image_id
Tile-cache key image id.
Definition mg_reader.h:138
int32_t fb_w
Framebuffer width, pixels.
Definition mg_reader.h:135
uint16_t tile_h
Atlas tile height, pixels.
Definition mg_reader.h:142
uint8_t fit_factor
Decimation factor for fit-page (>= 1).
Definition mg_reader.h:148
uint16_t tile_w
Atlas tile width, pixels.
Definition mg_reader.h:141
uint16_t page_h
Full page height, pixels.
Definition mg_reader.h:140
uint16_t * fb
RGB565 panel framebuffer.
Definition mg_reader.h:134
int32_t fb_h
Framebuffer height, pixels.
Definition mg_reader.h:136
uint16_t page_w
Full page width, pixels.
Definition mg_reader.h:139
ra8_tile_cache_t * cache
Tile cache paging the atlas.
Definition mg_reader.h:137
uint8_t zoom
Current mg_zoom_t.
Definition mg_reader.h:147
uint16_t tile_cols
Atlas tile columns.
Definition mg_reader.h:143
uint16_t tile_rows
Atlas tile rows.
Definition mg_reader.h:144
ra8_tile_pan_dir_t last_pan
Last pan direction (mg_reader_prefetch seed).
Definition mg_reader.h:149
Decode-on-miss context bound into the tile cache (DIP seam).
Definition mg_reader.h:101
const jof_info_t * info
Parsed atlas geometry.
Definition mg_reader.h:102
jof_pread_fn pread
Atlas positioned-read seam.
Definition mg_reader.h:103
uint8_t * scratch
Deflate stored-stream staging.
Definition mg_reader.h:105
void * pread_ctx
Context for pread.
Definition mg_reader.h:104
uint32_t scratch_cap
Capacity of scratch.
Definition mg_reader.h:106
Identifies one decoded image tile.
uint16_t tile_y
Tile row index (in tile units).
uint16_t tile_x
Tile column index (in tile units).
A predictive pan-prefetch request: what is visible + where it heads.
A pinned view of a cached tile returned by ra8_tile_cache_get.
const uint8_t * pixels
Decoded tile pixels (cell payload).
uint16_t height
Decoded tile height in pixels.
uint16_t width
Decoded tile width in pixels.