CHGame 0.3.0
Libraries for the CHGame handheld
Loading...
Searching...
No Matches
Mask.h
Go to the documentation of this file.
1/// @file Mask.h
2/// @brief 1 bpp scratch masks for outlined, shadowed and gradient lettering and logos.
3///
4/// Outlined, shadowed or gradient text drawn the naive way (the glyphs nine
5/// times over, pixel by pixel from flash) costs ~5 ms a line on this chip.
6/// Instead: render the shape once into a bit mask, grow it by one pixel with
7/// byte-wide ORs for the outline, and paint every row straight into the
8/// framebuffer, two pixels a byte. Still 5-10 ms for big lettering: draw it
9/// once onto still screens, not every frame.
10///
11/// CHGfx 1.3's gfx_textFx() works the same way and draws the same pixels with
12/// CHGfx_Tiny3x5, but brings CHGfx's whole GFXfont text path: about 2 KB more
13/// flash than this and Draw's 3x5 font.
14#pragma once
15#include <stdint.h>
16
17/// @defgroup chgame_mask Lettering masks
18/// @ingroup lib_chgame
19/// @brief Outlined, shadowed and gradient lettering, logos and the cover titles.
20///
21/// The mask lives in CHGfx's chunk buffers (gfx_chunkScratch, 1 KB), which
22/// are idle between gfx_wait() and the next flush - i.e. while drawing.
23/// Never keep a Mask across frames or use one outside drawing. Masks paint
24/// anywhere on screen: they ignore CHGfx's clip rectangle.
25///
26/// @code
27/// Mask m = maskBegin(text35WidthScaled("WIN", 3), 6 * 3);
28/// maskText35(m, 0, 0, "WIN", 3);
29/// maskDraw(m, 40, 50, GOLD, INK, WINE); // fill, outline, shadow
30/// @endcode
31/// @{
32
33/// @brief A 1 bpp shape being built in the chunk scratch. Made by maskBegin().
34struct Mask {
35 uint8_t *bits; ///< MSB-first rows, 1 px margin on every side.
36 uint8_t stride; ///< Bytes per row.
37 uint8_t w, h; ///< Usable size (excluding the margin).
38};
39
40/// @brief Start an empty mask in the chunk scratch.
41/// @param w,h Usable size in pixels; with the 1 px margin, (w + 2) x (h + 2)
42/// must fit in 1 KB of bits (about 8000 px).
43/// @return The mask, cleared. Valid until the next flush or the next
44/// maskBegin() (or anything else that uses gfx_chunkScratch()).
45Mask maskBegin(int w, int h); // cleared; (w + 2) x (h + 2) <= ~8000 px
46
47/// @brief Add text in the 3x5 font to a mask, at an integer scale.
48/// @param m The mask.
49/// @param x,y Top-left of the text inside the mask.
50/// @param s The text ('~' is a half space).
51/// @param scale Size: each font pixel becomes scale x scale (4*scale px
52/// advance, 6*scale rows with the descender).
53/// @param dy Optional: a vertical offset for each character (wavy banners).
54void maskText35(Mask &m, int x, int y, const char *s, uint8_t scale = 1, const int8_t *dy = nullptr);
55/// @brief The width of 3x5 text at a scale, for sizing a mask.
56/// @param s The text.
57/// @param scale The scale given to maskText35().
58/// @return text35Width(s) * scale.
59int text35WidthScaled(const char *s, uint8_t scale);
60/// @brief Add a 1 bpp bitmap (a logo) to a mask.
61/// @param m A mask begun at w*scale x h*scale.
62/// @param bits The bitmap: MSB-first rows of (w + 7) / 8 bytes, zero padding bits.
63/// @param w,h Its size in pixels.
64/// @param scale Each bitmap pixel becomes scale x scale.
65void maskBlit1(Mask &m, const uint8_t *bits, uint8_t w, uint8_t h, uint8_t scale = 1);
66
67/// @brief Paint a mask, with an optional outline, shadow and gradient.
68/// @param m The mask.
69/// @param x,y Where its top-left (inside the margin) goes on screen.
70/// @param fill Colour of the shape.
71/// @param outline Colour of a 1 px ring around it (all 8 directions), or -1 for none.
72/// @param shadow Colour of a shadow, or -1 for none: the outline moved a pixel
73/// down and right, or without an outline the shape moved so.
74/// @param ramp Optional: a fill colour for each mask row, replacing fill
75/// (gradient lettering).
76void maskDraw(const Mask &m, int x, int y, uint8_t fill, int outline = -1, int shadow = -1,
77 const uint8_t *ramp = nullptr);
78/// @brief Paint just the shape in one colour (no outline, no shadow).
79/// @param m The mask.
80/// @param x,y Where its top-left goes on screen.
81/// @param c Colour.
82void maskPaint(const Mask &m, int x, int y, uint8_t c);
83
84/// @brief Paint a title as the covers set it, in the house gold.
85/// @details (docs/cover-art.md, "the stack".) The shape extruded `depth` px
86/// down and right in `side`, an INK outline round letters and extrusion
87/// together, thickened a pixel down and right (the drop shadow), and the face
88/// a smooth gradient. A one-pixel gap between letters stays INK. About twice
89/// a maskDraw(): draw it onto still screens where the game can.
90/// @param m The mask holding the lettering.
91/// @param x,y Where its top-left goes on screen.
92/// @param base The face's base colour.
93/// @param ramp A byte for each mask row: a colour (high nibble) laid over
94/// `base` where the row's dither pattern (low nibble, MSB the
95/// first of every 4 pixels from the lettering's left; 0 none,
96/// 15 all) has bits. tools/titleart.py works the patterns out of
97/// a 4x4 ordered dither.
98/// @param depth The extrusion in pixels, at most 4.
99/// @param side The extrusion's colour.
100void maskTitle(const Mask &m, int x, int y, uint8_t base, const uint8_t *ramp, uint8_t depth, uint8_t side);
101/// @brief Paint a game's title from the arrays tools/titleart.py writes from its
102/// cover recipe: maskBegin(), maskBlit1() and maskTitle() in one call.
103/// @param bits The 1 bpp lettering (as maskBlit1()).
104/// @param w,h Its size in pixels.
105/// @param x,y Where its top-left goes on screen.
106/// @param base The face's base colour.
107/// @param ramp The gradient, a byte a row (as maskTitle()).
108/// @param depth The extrusion in pixels, at most 4.
109/// @param side The extrusion's colour.
110void titleArt(const uint8_t *bits, uint8_t w, uint8_t h, int x, int y, uint8_t base, const uint8_t *ramp,
111 uint8_t depth, uint8_t side);
112
113/// @}
void maskTitle(const Mask &m, int x, int y, uint8_t base, const uint8_t *ramp, uint8_t depth, uint8_t side)
Paint a title as the covers set it, in the house gold.
void titleArt(const uint8_t *bits, uint8_t w, uint8_t h, int x, int y, uint8_t base, const uint8_t *ramp, uint8_t depth, uint8_t side)
Paint a game's title from the arrays tools/titleart.py writes from its cover recipe: maskBegin(),...
void maskBlit1(Mask &m, const uint8_t *bits, uint8_t w, uint8_t h, uint8_t scale=1)
Add a 1 bpp bitmap (a logo) to a mask.
int text35WidthScaled(const char *s, uint8_t scale)
The width of 3x5 text at a scale, for sizing a mask.
void maskText35(Mask &m, int x, int y, const char *s, uint8_t scale=1, const int8_t *dy=nullptr)
Add text in the 3x5 font to a mask, at an integer scale.
void maskPaint(const Mask &m, int x, int y, uint8_t c)
Paint just the shape in one colour (no outline, no shadow).
void maskDraw(const Mask &m, int x, int y, uint8_t fill, int outline=-1, int shadow=-1, const uint8_t *ramp=nullptr)
Paint a mask, with an optional outline, shadow and gradient.
Mask maskBegin(int w, int h)
Start an empty mask in the chunk scratch.
A 1 bpp shape being built in the chunk scratch. Made by maskBegin().
Definition Mask.h:34
uint8_t * bits
MSB-first rows, 1 px margin on every side.
Definition Mask.h:35
uint8_t h
Usable size (excluding the margin).
Definition Mask.h:37
uint8_t stride
Bytes per row.
Definition Mask.h:36