Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
f1e3710
chore(bmfonts): namespace fixture fonts with source prefixes
dpt Sep 10, 2026
e66c624
refactor(wuss): rename ICON_TYPE_BUTTON to ACTION, reserve new icon t…
dpt Sep 10, 2026
ab8d3b7
refactor(wuss): drop wuss_icon.window; add per-type data union
dpt Sep 10, 2026
490daa8
refactor(wuss): give wuss_icon_spec the same per-type union as the icon
dpt Sep 10, 2026
2fcda05
fix(wuss): scroll the gradient task's matrix-size label with the content
dpt Sep 10, 2026
4b3c922
fix(wuss): scroll curve and porter-duff task content with the document
dpt Sep 10, 2026
143990d
refactor(wuss): nest wuss_icon_spec inside struct wuss_icon
dpt Sep 10, 2026
5071d26
docs: rewrap Doxygen comments to column limit
dpt Sep 10, 2026
57c4287
refactor(wuss): move fonts into a core-owned wuss/font module
dpt Sep 10, 2026
aa1c52b
docs(wuss): describe the font module
dpt Sep 10, 2026
af13876
feat(framebuf): add ordered-dither variant of screen_copy_bitmap
dpt Sep 10, 2026
3ab387d
fix(wuss): close submenus when the parent menu's title bar is hovered
dpt Sep 10, 2026
1a59508
feat(wuss): add wuss_EVENT_POINTER_ENTER / wuss_EVENT_POINTER_EXIT
dpt Sep 10, 2026
8c6431d
fix(wuss): size radio/option glyph box from the state sprite
dpt Sep 10, 2026
89b32b2
perf(framebuf): hoist dither divide out of the paletted blit inner loop
dpt Sep 10, 2026
eb72244
fix(framebuf): key blit dither on sprite-local coordinates
dpt Sep 10, 2026
af99859
fix(framebuf): support 1bpp and 2bpp screens in screen_copy_rect
dpt Sep 10, 2026
24f2094
fix(framebuf): match house within-byte pixel order in screen_copy_rec…
dpt Sep 10, 2026
78ed9e4
fix(wuss): keep a menu-opened window on screen
dpt Sep 10, 2026
2126ef0
fix(wuss): refresh the whole radio/option icon on select
dpt Sep 10, 2026
96a4029
fix(wuss): don't close a submenu dragged over its parent's titlebar
dpt Sep 10, 2026
68cc2a0
fix(wuss): update the chars grid's doc extent on font switch
dpt Sep 10, 2026
def8aa8
feat(framebuf): add 8bpp paletted (p8) screen support
dpt Sep 11, 2026
be0c392
feat(wuss): add screen-palette window; fix(framebuf): p8 image colour…
dpt Sep 11, 2026
2e6e133
feat(wuss): fill p8 screen palette tail with the web-safe 216
dpt Sep 11, 2026
abb6184
fix(wuss): pad screen palette on live palette change, not just startup
dpt Sep 11, 2026
baeb980
fix(framebuf): key ordered-dither bias on per-channel levels, not ent…
dpt Sep 11, 2026
98cc4d7
fix(framebuf): reject paletted source bitmaps in screen_copy_bitmap
dpt Sep 11, 2026
9eadfe3
feat(framebuf): support paletted source bitmaps in screen_copy_bitmap
dpt Sep 11, 2026
701f940
refactor(framebuf): hoist has-alpha-channel check into pixelfmt_has_a…
dpt Sep 11, 2026
510dd97
feat(bmfont): draw text at baseline, not glyph-cell top-left
dpt Sep 11, 2026
399fc95
feat(wuss): expose wuss_text_draw/wuss_text_measure as public API
dpt Sep 11, 2026
3ffe645
refactor(wuss): reuse array_grow/alloc_strdup helpers in icon module
dpt Sep 11, 2026
255c6a1
refactor(wuss)!: rework menu tick API into data-level and live variants
dpt Sep 11, 2026
ba9f063
refactor(wuss)!: menu-desc !/~ pull bool vararg instead of always app…
dpt Sep 11, 2026
83b5503
fix(wuss): clamp blit-shifted pieces to content box before invalidating
dpt Sep 11, 2026
2b3150a
feat(wuss): add background colour menu to image task
dpt Sep 11, 2026
20457ef
feat(wuss): add grid-size menu to minesweeper task
dpt Sep 11, 2026
46a97ff
fix(wuss): cap interactive resize-drag at the screen size
dpt Sep 11, 2026
5f46d54
fix(bitmap): drop mkstemps from rle-test, use fixed leafname
dpt Sep 12, 2026
65cca4d
fix(io): match RISC OS leafnames' lack of dotted extensions
dpt Sep 12, 2026
3d1b82f
fix(io): stop path_join_leafname appending a bogus RISC OS separator
dpt Sep 12, 2026
befe9a5
feat(wuss): add Shift-F1 for wuss_INPUT_GARBAGE on RISC OS frontend
dpt Sep 12, 2026
93c02ca
fix(wuss): partial-redraw minesweeper to stop board flicker
dpt Sep 12, 2026
4a159d9
fix(wuss): stop invalidate-visible double-applying scroll on NULL box
dpt Sep 12, 2026
3eff11c
fix(wuss): correct off-by-one in ball edge-clamp on right/bottom
dpt Sep 12, 2026
875f36a
fix(wuss): clamp wuss_window_invalidate to the window's content area
dpt Sep 12, 2026
b11885a
perf(wuss): translate cached furniture layout on move instead of rebu…
dpt Sep 12, 2026
4b47c21
perf(wuss): skip a window move that changes nothing
dpt Sep 12, 2026
ccdc2da
perf(wuss): skip a window resize that changes nothing
dpt Sep 12, 2026
9a0c2dd
fix(wuss): exclude stale dirty regions from resize scroll-reclamp blit
dpt Sep 12, 2026
876b0eb
fix(wuss): guard resize scroll-reclamp blit against piece-budget over…
dpt Sep 12, 2026
1a1dc17
fix(wuss): remove duplicate chrome repaint on scroll-reclamp resize
dpt Sep 12, 2026
2ed2170
feat(wuss): ADJUST-click in a scroll well pages away from the pointer
dpt Sep 12, 2026
a3231e8
fix(wuss): don't arm a sausage drag on a scroll-well click
dpt Sep 12, 2026
31ffe31
perf(wuss): convert only dirty rows on SDL present
dpt Sep 13, 2026
18031f3
fix(wuss): allow sausage drag arming on a direct sausage hit
dpt Sep 13, 2026
1ae9025
fix(wuss): track blit-touched regions so partial present stops going …
dpt Sep 13, 2026
5e55d31
feat(wuss): saturn task gets a Colours menu for fg/bg
dpt Sep 13, 2026
9aeef13
feat(wuss): add wuss_ICON_TYPE_SLIDER
dpt Sep 13, 2026
bb85d4e
feat(wuss): saturn task gets a Size... submenu
dpt Sep 13, 2026
75216ab
fix(wuss): saturn Size dialogue buttons act on Select release
dpt Sep 13, 2026
3c35d43
feat(geom): add stack module for box-stack layout
dpt Sep 13, 2026
e905281
test(geom): add 10 stack layout tests with ASCII diagrams
dpt Sep 14, 2026
7cbf5df
feat(wuss): saturn size dialogue laid out via stack_solve
dpt Sep 14, 2026
f3753ec
feat(geom): add STACK_* macros for compact stack_item_t tables
dpt Sep 14, 2026
f4edd55
refactor(wuss): reduce duplication in saturn.c
dpt Sep 14, 2026
f5fafde
feat(wuss)!: flip furniture window flags to opt-in
dpt Sep 14, 2026
2f59a69
fix(wuss): slider groove derives from the surround box, not the bevel…
dpt Sep 14, 2026
01715ff
refactor(wuss): drop redundant size-dialogue redraw guard in saturn_h…
dpt Sep 14, 2026
5b5e9be
style: order static const locals before regular locals in scope
dpt Sep 14, 2026
ff0394c
refactor(wuss): scale saturn's sample space with window size
dpt Sep 14, 2026
ec7e30f
refactor(wuss): move std icon-size constants to icon.h
dpt Sep 14, 2026
2169b8d
refactor(wuss): factor icon-spec fill helpers out of saturn_size_dial…
dpt Sep 14, 2026
be2fc43
refactor(wuss): add wuss_STD_GAP/wuss_STD_INSET, replace saturn.c's l…
dpt Sep 15, 2026
fb2d9a4
feat(wuss): baseline rule, blank-row trim and inset in the chars task
dpt Sep 15, 2026
793aaa8
fix(wuss): vertically centre icon text by ascender only
dpt Sep 15, 2026
1b4e155
refactor(wuss): factor icon text baseline-y centring into a helper
dpt Sep 15, 2026
4f36d25
feat(wuss): show advance width as a light-blue rule in the chars task
dpt Sep 15, 2026
c672c01
fix(wuss): update fonts for reduced advance width
dpt Sep 15, 2026
010632c
fix(tools): ttf2bmfont ink-advance mode no longer adds a spurious pixel
dpt Sep 15, 2026
bb16d50
fix(bmfont): add back 1px letter spacing removed from advance widths
dpt Sep 15, 2026
abacdcd
fix(wuss): restore furniture on swatches/text/palette task windows
dpt Sep 15, 2026
00588b7
fix(bmfont): stop clipping full-width glyphs out of existence
dpt Sep 15, 2026
c95bb83
feat(wuss): add iterations slider to saturn size dialogue
dpt Sep 15, 2026
caebc44
feat(bmfont): add letter and word spacing options
dpt Sep 15, 2026
311c3ac
docs(changelog): record work since wuss-picklepuss merge
dpt Sep 15, 2026
8347cd9
feat(wuss): add ring and body iteration sliders to saturn size dialogue
dpt Sep 15, 2026
3c165fc
refactor(wuss): fold slider task into icons work-area demo
dpt Sep 15, 2026
ebdc739
docs(wuss): note slider client-side snapping and pointer drift
dpt Sep 15, 2026
d7dd949
refactor(wuss): rename saturn Size dialogue to Configuration
dpt Sep 15, 2026
ad06443
refactor(wuss): introduce slider-row abstraction, use in saturn size …
dpt Sep 15, 2026
7127d86
refactor(wuss): centralise slider-row snapping via a step field
dpt Sep 15, 2026
e05d74a
fix(wuss): stop spurious MOUSE_MOVE icon events on a slider under hover
dpt Sep 15, 2026
b83fd68
refactor(wuss): group saturn conf fields, size dialogue from stack_sm…
dpt Sep 15, 2026
cb64317
refactor(wuss): invert window titlebar/outline flags to NO_ variants
dpt Sep 16, 2026
3ce7016
feat(wuss): add dialogue component, refactor saturn Configure onto it
dpt Sep 16, 2026
8e7411a
feat(wuss): add relayoutable wuss_info_t, shared wuss_proginfo_t dial…
dpt Sep 16, 2026
e273f49
fix(bmfonts): Fix MS Sans Serif advance widths
dpt Sep 16, 2026
7202338
feat(wuss): add Info row to Saturn task's menu
dpt Sep 16, 2026
a6593a9
refactor(geom): tighten stack solver declaration alignment
dpt Sep 16, 2026
e4e4fa1
style: tighten declaration-block alignment across libraries/
dpt Sep 16, 2026
ab55dc0
chore: move formatting scripts to tools/fmt/
dpt Sep 16, 2026
85eba08
docs: fix tools/fmt path in CLAUDE.md
dpt Sep 16, 2026
dddbc4b
test: move tool self-checks to tools/fmt/, add one for realign_decls
dpt Sep 16, 2026
72120d5
style: rewrap prototype alignment via wrap_protos.py
dpt Sep 16, 2026
6545643
refactor(wuss): return task pointer and add X_destroy from all demo t…
dpt Sep 16, 2026
882931b
feat(wuss): add wuss_get_resources, drop resources param from demo tasks
dpt Sep 16, 2026
226035b
refactor(wuss): normalize demo task X_create to (wuss, out)
dpt Sep 16, 2026
2bfdbbe
feat(wuss): rename global g to g_tasks, spawn Saturn at startup
dpt Sep 16, 2026
6074986
fix(wuss): scale saturn's energy-gate constants with window size
dpt Sep 16, 2026
d2f32e6
feat(wuss): add Default button to saturn's config dialogue
dpt Sep 16, 2026
d9ff212
feat(wuss): split demo launcher into Games/Tests/Utilities/Visuals
dpt Sep 16, 2026
92ca06a
fix(bmfonts): Reduce Digits Bold space width
dpt Sep 16, 2026
c786704
feat(wuss): add letter/word spacing, colour and background controls t…
dpt Sep 16, 2026
d8922bf
docs: update CHANGELOG for work since 311c3ac
dpt Sep 16, 2026
75d5075
fix(wuss): clamp reversed slider-row snap correctly
dpt Sep 16, 2026
89f35a5
fix(wuss): cap colourmenu swatch generation below the symbolic namespace
dpt Sep 16, 2026
c4db36c
fix(wuss): let disabled menu rows still collapse an open sibling submenu
dpt Sep 16, 2026
08c1f50
fix(wuss): guard wuss_dialogue_handle_icon against NULL dialogue/event
dpt Sep 16, 2026
6efdcc2
perf(wuss): add n<=1 fast path to wuss__order_pieces
dpt Sep 16, 2026
2b0b999
refactor(wuss): de-duplicate clip_to_visible/subtract_boxes carve loops
dpt Sep 16, 2026
2b85beb
refactor(wuss): de-duplicate settled-vs-stale pixel filtering
dpt Sep 16, 2026
48e3334
fix(wuss): enforce WUSS_MIN_SAUSAGE floor when the well is shorter th…
dpt Sep 16, 2026
2ba12e3
fix(wuss): guard wuss_proginfo_set_desc against NULL pi/desc
dpt Sep 16, 2026
8210d00
style(wuss): reorder wuss_window_resize locals by first use
dpt Sep 16, 2026
085c420
docs: update CHANGELOG for code-review fixes
dpt Sep 16, 2026
05cfce7
fix(geom): replace stack solver VLAs with a fixed STACK_MAX_ITEMS cap
dpt Sep 16, 2026
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
321 changes: 321 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ New source/header files must be added by hand to the relevant `set(..._SOURCES .
- Section breaks within files use `/* ----- ... ----- */` rule comments.
- Public API docs use Doxygen (`\file`, `\param`, `\return`); a `Doxyfile` exists for generating them.
- Edit `.c`/`.h` files with the Edit tool, never `sed -i` line-range splices — they corrupt the Allman/2-space layout and can't be verified without re-reading. To inspect exact bytes or indentation, Read the file; don't shell out to `cat -A`/`cat -v`.
- After editing any `.c`/`.h` function prototype or definition, run `python3 tools/wrap_protos.py <file>`; after editing a header's Doxygen, run `python3 tools/wrap_doxygen.py <file>` (skip vendored headers).
- After editing any `.c`/`.h` function prototype or definition, run `python3 tools/fmt/wrap_protos.py <file>`; after editing a header's Doxygen, run `python3 tools/fmt/wrap_doxygen.py <file>` (skip vendored headers).
- Before committing any `.c`/`.h` changes, run `python3 tools/fmt/realign_decls.py <file>` (declaration-block alignment) alongside `wrap_protos.py`/`wrap_doxygen.py` on the same files.

## Commit messages

Expand Down
26 changes: 21 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ set(PUBLIC_HEADERS
include/framebuf/span-p1.h
include/framebuf/span-p2.h
include/framebuf/span-p4.h
include/framebuf/span-p8.h
include/framebuf/span-registry.h
include/framebuf/span-rgba8888.h
include/framebuf/span-rgbx8888.h
Expand All @@ -103,6 +104,7 @@ set(PUBLIC_HEADERS
include/geom/packer.h
include/geom/point.h
include/geom/size.h
include/geom/stack.h
include/io/dirscan.h
include/io/namelist.h
include/io/path.h
Expand Down Expand Up @@ -130,6 +132,7 @@ set(PUBLIC_HEADERS

if(WUSS_ICONS)
list(APPEND PUBLIC_HEADERS include/wuss/icon.h)
list(APPEND PUBLIC_HEADERS include/wuss/icon-spec.h)
endif()
if(WUSS_MENUS)
list(APPEND PUBLIC_HEADERS include/wuss/menu.h)
Expand All @@ -140,6 +143,7 @@ if(WUSS_COMPONENTS)
list(APPEND PUBLIC_HEADERS include/wuss/component/colourmenu.h)
list(APPEND PUBLIC_HEADERS include/wuss/component/info.h)
list(APPEND PUBLIC_HEADERS include/wuss/component/proginfo.h)
list(APPEND PUBLIC_HEADERS include/wuss/component/dialogue.h)
endif()

# The public headers must be set as properties of the library, not as
Expand Down Expand Up @@ -286,6 +290,7 @@ set(FRAMEBUF_SOURCES
libraries/framebuf/span/p1.c
libraries/framebuf/span/p2.c
libraries/framebuf/span/p4.c
libraries/framebuf/span/p8.c
libraries/framebuf/span/rgbx8888.c
libraries/framebuf/span/xbgr8888.c)

Expand All @@ -308,7 +313,11 @@ set(GEOM_SOURCES
libraries/geom/layout/layout.c
libraries/geom/line/line.c
libraries/geom/packer/impl.h
libraries/geom/packer/packer.c)
libraries/geom/packer/packer.c
libraries/geom/stack/impl.h
libraries/geom/stack/measure-min.c
libraries/geom/stack/solve.c
libraries/geom/stack/valid-tree.c)

set(IO_SOURCES
libraries/io/dirscan/dirscan.c
Expand Down Expand Up @@ -371,9 +380,9 @@ set(WUSS_CORE_SOURCES
libraries/wuss/core/backdrop.c
libraries/wuss/core/create.c
libraries/wuss/core/destroy.c
libraries/wuss/core/get-font.c
libraries/wuss/core/get-palette.c
libraries/wuss/core/get-pointer.c
libraries/wuss/core/get-resources.c
libraries/wuss/core/idle.c
libraries/wuss/core/impl.h
libraries/wuss/core/invalidate.c
Expand All @@ -386,7 +395,9 @@ set(WUSS_CORE_SOURCES
libraries/wuss/core/scroll-step.c
libraries/wuss/core/set-backdrop.c
libraries/wuss/core/set-palette.c
libraries/wuss/core/text.c
libraries/wuss/font/font.h
libraries/wuss/font/registry.c
libraries/wuss/font/text.c
libraries/wuss/core/task/create.c
libraries/wuss/core/task/destroy.c
libraries/wuss/core/task/set-autoclose.c
Expand Down Expand Up @@ -433,11 +444,12 @@ set(WUSS_ICON_SOURCES
libraries/wuss/icon/draw.c
libraries/wuss/icon/free.c
libraries/wuss/icon/from-spec.c
libraries/wuss/helpers/icon-spec.c
libraries/wuss/icon/get-bbox.c
libraries/wuss/icon/get-selected.c
libraries/wuss/icon/get-text.c
libraries/wuss/icon/get-type.c
libraries/wuss/icon/get-window.c
libraries/wuss/icon/get-value.c
libraries/wuss/icon/hit-test.c
libraries/wuss/icon/invalidate.c
libraries/wuss/icon/plot.c
Expand All @@ -447,6 +459,8 @@ set(WUSS_ICON_SOURCES
libraries/wuss/icon/set-hover.c
libraries/wuss/icon/set-selected.c
libraries/wuss/icon/set-text.c
libraries/wuss/icon/set-value.c
libraries/wuss/icon/slider-box.c
libraries/wuss/icon.h)

set(WUSS_MENU_SOURCES
Expand All @@ -458,7 +472,8 @@ set(WUSS_COMPONENT_SOURCES
libraries/wuss/component/fontmenu.c
libraries/wuss/component/colourmenu.c
libraries/wuss/component/info.c
libraries/wuss/component/proginfo.c)
libraries/wuss/component/proginfo.c
libraries/wuss/component/dialogue.c)

set(WUSS_SOURCES ${WUSS_CORE_SOURCES})
if(WUSS_FURNITURE)
Expand Down Expand Up @@ -682,6 +697,7 @@ if(BUILD_TESTS)
libraries/geom/box/test/box-test.c
libraries/geom/layout/test/layout-test.c
libraries/geom/packer/test/packer-test.c
libraries/geom/stack/test/stack-test.c
libraries/io/stream/test/stream-test.c
libraries/text/txtfmt/test/txtfmt-test.c
libraries/utils/array/test/array-test.c
Expand Down
1 change: 1 addition & 0 deletions apps/test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static const test_t tests[] =
{ "box", box_test },
{ "layout", layout_test },
{ "packer", packer_test },
{ "stack", stack_test },

{ "stream", stream_test },

Expand Down
27 changes: 24 additions & 3 deletions apps/wuss/frontend-riscos.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,14 @@ static wuss_button_t mouse_buttons_to_wuss(int buttons)
return b;
}

/* INKEY scan codes for keys tested individually, outside g_keys[] below: F1
* (checked with Shift to pick REDRAW_ALL vs GARBAGE) and Shift itself. */
#define KEY_SCAN_F1 (-114)
#define KEY_SCAN_SHIFT (-1)

/* Keys the demo reacts to: negative INKEY scan code -> input kind. F4 and
* Escape both quit. */
* Escape both quit. F1 is handled separately in wuss_frontend_poll, not in
* this table, so it can vary its kind with Shift. */
static const struct
{
int scan;
Expand All @@ -223,7 +229,6 @@ static const struct
g_keys[] =
{
{ -113, wuss_INPUT_QUIT }, /* Escape */
{ -114, wuss_INPUT_REDRAW_ALL }, /* F1 */
{ -116, wuss_INPUT_PIXEL_STRESS }, /* F3 */
{ -117, wuss_INPUT_QUIT } /* F4 */
};
Expand All @@ -242,6 +247,7 @@ bool wuss_frontend_poll(wuss_frontend_t *fe, wuss_input_t *event)
static unsigned int key_was; /* bit i = g_keys[i] was down last poll */

unsigned int key_now = 0;
unsigned int f1_bit = 1u << NELEMS(g_keys); /* one bit past the table */
int mx, my, buttons, t;
int px, py;
size_t i;
Expand All @@ -251,6 +257,18 @@ bool wuss_frontend_poll(wuss_frontend_t *fe, wuss_input_t *event)
for (i = 0; i < NELEMS(g_keys); i++)
if (key_down(g_keys[i].scan))
key_now |= 1u << i;
if (key_down(KEY_SCAN_F1))
key_now |= f1_bit;

/* F1 is handled here rather than in g_keys[]: its kind depends on Shift,
* which a static table entry can't express. */
if ((key_now & f1_bit) && !(key_was & f1_bit))
{
key_was = key_now;
event->kind = key_down(KEY_SCAN_SHIFT) ? wuss_INPUT_GARBAGE
: wuss_INPUT_REDRAW_ALL;
return true;
}

for (i = 0; i < NELEMS(g_keys); i++)
{
Expand Down Expand Up @@ -313,10 +331,13 @@ bool wuss_frontend_poll(wuss_frontend_t *fe, wuss_input_t *event)
return false;
}

void wuss_frontend_present(wuss_frontend_t *fe, const bitmap_t *bm)
void wuss_frontend_present(wuss_frontend_t *fe,
const bitmap_t *bm,
const box_t *dirty)
{
NOT_USED(fe);
NOT_USED(bm);
NOT_USED(dirty);

/* wuss drew straight into screen memory; just pace to the frame rate */
_swix(OS_Byte, _IN(0), 19);
Expand Down
116 changes: 75 additions & 41 deletions apps/wuss/frontend-sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
#include "frontend.h"

/* Screen pixel format for the demo, chosen at run time via --depth: 32 =
* pixelfmt_bgrx8888 (feeds SDL directly, no per-frame conversion); 4 (the
* default) = pixelfmt_p4 paletted (exercises screen_copy_rect's nibble-packed
* blit path instead); 2 = pixelfmt_p2; 1 = pixelfmt_p1 monochrome. Paletted
* depths are converted to bgrx8888 per frame via bitmap_convert. Stashed in
* struct wuss_frontend so present() can branch on it. */
* pixelfmt_bgrx8888 (feeds SDL directly, no per-frame conversion); 8 =
* pixelfmt_p8; 4 (the default) = pixelfmt_p4 paletted (exercises
* screen_copy_rect's nibble-packed blit path instead); 2 = pixelfmt_p2; 1 =
* pixelfmt_p1 monochrome. Paletted depths are converted to bgrx8888 per
* frame via bitmap_convert. Stashed in struct wuss_frontend so present() can
* branch on it. */

/* Integer window zoom: the fixed Wuss screen is drawn at this many device
* pixels per screen pixel. The initial value comes from -scale (0 => use the
Expand All @@ -47,7 +48,7 @@ struct wuss_frontend
int scr_width;
int scr_height;
int scale; /* device pixels per screen pixel; see WUSS_SDL_*_SCALE */
int depth; /* framebuffer bits per pixel: 32 (bgrx8888), 4 (p4), 2 (p2) or 1 (p1) */
int depth; /* framebuffer bits per pixel: 32 (bgrx8888), 8 (p8), 4 (p4), 2 (p2) or 1 (p1) */
void *pixels; /* the private framebuffer handed to the caller */
};

Expand Down Expand Up @@ -100,20 +101,18 @@ result_t wuss_frontend_open(int width,
NOT_USED(palette);
NOT_USED(npalette);

if (depth != 1 && depth != 2 && depth != 4 && depth != 32)
if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 32)
{
fprintf(stderr, "Error: unsupported depth %d (want 1, 2, 4 or 32)\n", depth);
fprintf(stderr,
"Error: unsupported depth %d (want 1, 2, 4, 8 or 32)\n", depth);
return result_BAD_ARG;
}

if (scale <= 0)
scale = WUSS_SDL_DEFAULT_SCALE;
scale = CLAMP(scale, WUSS_SDL_MIN_SCALE, WUSS_SDL_MAX_SCALE);

stride = (depth == 32) ? width * 4 /* pixelfmt_bgrx8888: 4 bytes/pixel */
: (depth == 4) ? width / 2 /* pixelfmt_p4: 2 pixels/byte */
: (depth == 2) ? (width + 3) / 4 /* pixelfmt_p2: 4 pixels/byte */
: (width + 7) / 8; /* pixelfmt_p1: 8 pixels/byte */
stride = (width * depth + 7) >> 3;

fe = calloc(1, sizeof(*fe));
if (fe == NULL)
Expand Down Expand Up @@ -165,6 +164,7 @@ result_t wuss_frontend_open(int width,
SDL_SetTextureScaleMode(fe->texture, SDL_SCALEMODE_NEAREST);

*fmt = (depth == 32) ? pixelfmt_bgrx8888
: (depth == 8) ? pixelfmt_p8
: (depth == 4) ? pixelfmt_p4
: (depth == 2) ? pixelfmt_p2
: pixelfmt_p1;
Expand Down Expand Up @@ -202,36 +202,42 @@ bool wuss_frontend_poll(wuss_frontend_t *fe, wuss_input_t *event)
return true;

case SDL_EVENT_KEY_UP:
if (ev.key.key == SDLK_F4)
event->kind = wuss_INPUT_QUIT;
else if (ev.key.key == SDLK_F1 && (ev.key.mod & SDL_KMOD_SHIFT))
event->kind = wuss_INPUT_GARBAGE;
else if (ev.key.key == SDLK_F1)
event->kind = wuss_INPUT_REDRAW_ALL;
else if (ev.key.key == SDLK_F3)
event->kind = wuss_INPUT_PIXEL_STRESS;
else if (ev.key.key == SDLK_F2)
switch (ev.key.key)
{
int scale;

/* F2 steps the SDL window zoom up, Shift-F2 down, clamped to
* [WUSS_SDL_MIN_SCALE, WUSS_SDL_MAX_SCALE]: a backend-local zoom the
* demo loop never sees. */
scale = fe->scale + ((ev.key.mod & SDL_KMOD_SHIFT) ? -1 : 1);
if (scale < WUSS_SDL_MIN_SCALE)
scale = WUSS_SDL_MIN_SCALE;
else if (scale > WUSS_SDL_MAX_SCALE)
scale = WUSS_SDL_MAX_SCALE;
if (scale != fe->scale)
case SDLK_F1:
event->kind = (ev.key.mod & SDL_KMOD_SHIFT)
? wuss_INPUT_GARBAGE
: wuss_INPUT_REDRAW_ALL;
break;
case SDLK_F2:
{
fe->scale = scale;
SDL_SetWindowSize(fe->window, fe->scr_width * scale,
fe->scr_height * scale);
int scale;

/* F2 steps the SDL window zoom up, Shift-F2 down, clamped to
* [WUSS_SDL_MIN_SCALE, WUSS_SDL_MAX_SCALE]: a backend-local zoom the
* demo loop never sees. */
scale = fe->scale + ((ev.key.mod & SDL_KMOD_SHIFT) ? -1 : 1);
if (scale < WUSS_SDL_MIN_SCALE)
scale = WUSS_SDL_MIN_SCALE;
else if (scale > WUSS_SDL_MAX_SCALE)
scale = WUSS_SDL_MAX_SCALE;
if (scale != fe->scale)
{
fe->scale = scale;
SDL_SetWindowSize(fe->window, fe->scr_width * scale,
fe->scr_height * scale);
}
continue;
}
case SDLK_F3:
event->kind = wuss_INPUT_PIXEL_STRESS;
break;
case SDLK_F4:
event->kind = wuss_INPUT_QUIT;
break;
default:
continue;
}
else
continue;
return true;

case SDL_EVENT_MOUSE_BUTTON_DOWN:
Expand Down Expand Up @@ -287,28 +293,56 @@ bool wuss_frontend_poll(wuss_frontend_t *fe, wuss_input_t *event)
}
}

void wuss_frontend_present(wuss_frontend_t *fe, const bitmap_t *bm)
void wuss_frontend_present(wuss_frontend_t *fe,
const bitmap_t *bm,
const box_t *dirty)
{
if (fe->depth == 32)
{
SDL_UpdateTexture(fe->texture, NULL, bm->base, bm->rowbytes);
}
else
{
bitmap_t *disp;
result_t rc;
bitmap_t rows, *disp;
int y0, y1;
SDL_Rect rect;

/* Sub-byte formats (p1/p2/p4) pack several pixels per byte, so only a
* whole-row crop is safe without redoing their bit-unpacking maths for an
* arbitrary x0; a dirty rect just narrows which rows get converted. */
y0 = (dirty != NULL) ? CLAMP(dirty->y0, 0, bm->size.h) : 0;
y1 = (dirty != NULL) ? CLAMP(dirty->y1, 0, bm->size.h) : bm->size.h;
if (y1 <= y0)
goto present;

rc = bitmap_init(&rows,
SIZE2D(bm->size.w, y1 - y0),
bm->format,
bm->rowbytes,
bm->palette,
(unsigned char *) bm->base + y0 * bm->rowbytes);
if (rc != result_OK)
goto present;

/* wuss draws into a paletted bitmap; SDL wants bgrx. bitmap_convert reads
* the palette straight off `bm`, which the caller updates when the palette
* task's picker menu changes it, so a live palette change just shows up in
* the next converted frame. */
if (bitmap_convert(bm, pixelfmt_bgrx8888, &disp) == result_OK)
if (bitmap_convert(&rows, pixelfmt_bgrx8888, &disp) == result_OK)
{
SDL_UpdateTexture(fe->texture, NULL, disp->base, disp->rowbytes);
rect.x = 0;
rect.y = y0;
rect.w = bm->size.w;
rect.h = y1 - y0;

SDL_UpdateTexture(fe->texture, &rect, disp->base, disp->rowbytes);
free(disp->base);
free(disp);
}
}

present:
SDL_RenderTexture(fe->renderer, fe->texture, NULL, NULL);
SDL_RenderPresent(fe->renderer);

Expand Down
Loading