summaryrefslogtreecommitdiff
path: root/chapter31/docs
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-11-11 11:49:04 -0800
committerCliff Click <cliffc@acm.org>2026-11-12 13:48:30 -0800
commitf4bac750504ae2d21068a87b6a6bf4a733476993 (patch)
tree644741a31d045d17f9456f07078a2fca2bb21412 /chapter31/docs
parenta269fa7e8aea51b4fbdd2f2c6c24e84ef26f9ca4 (diff)
downloadSimple-f4bac750504ae2d21068a87b6a6bf4a733476993.tar.gz
Simple-f4bac750504ae2d21068a87b6a6bf4a733476993.zip
First cut graphics
Diffstat (limited to 'chapter31/docs')
-rw-r--r--chapter31/docs/examples/Graphics.smp17
-rw-r--r--chapter31/docs/examples/README.md4
-rw-r--r--chapter31/docs/graphics.md109
3 files changed, 129 insertions, 1 deletions
diff --git a/chapter31/docs/examples/Graphics.smp b/chapter31/docs/examples/Graphics.smp
new file mode 100644
index 00000000..7ba5c6e7
--- /dev/null
+++ b/chapter31/docs/examples/Graphics.smp
@@ -0,0 +1,17 @@
+// Optional graphics smoke test: pixels are drawn entirely in Simple.
+// Pass any argument for a short, self-closing test; otherwise close or press Esc.
+val main = { u8[~][] args ->
+ if( sys.gfx.open("Simple pixels",320,240) != sys.gfx.OK ) return 1;
+ val pixels = new u32[320*240];
+ for( int y=0; y<240; y++ )
+ for( int x=0; x<320; x++ )
+ pixels[y*320+x] = (x*255/319 << 16) | (y*255/239 << 8) | 64;
+ int result = sys.gfx.present(pixels);
+ int frames = 0;
+ while( result == sys.gfx.OK ) {
+ result = sys.gfx.poll(true);
+ if( args# > 1 && ++frames == 5 ) break;
+ }
+ sys.gfx.close();
+ return result == sys.gfx.ERROR ? 1 : 0;
+};
diff --git a/chapter31/docs/examples/README.md b/chapter31/docs/examples/README.md
index 58f7817b..2f19f09c 100644
--- a/chapter31/docs/examples/README.md
+++ b/chapter31/docs/examples/README.md
@@ -1,7 +1,9 @@
# Runnable examples
These programs live beside the documentation so readers can find and run them.
-Their native regression tests still run as part of `make tests`.
+Their non-graphical native regression tests run as part of `make tests`.
+The optional [pixel-window example](Graphics.smp) uses MiniFB; see
+[graphics setup](../graphics.md). `make run-graphics` opens it explicitly.
From `chapter31`, build the tic-tac-toe executable (without starting it):
diff --git a/chapter31/docs/graphics.md b/chapter31/docs/graphics.md
new file mode 100644
index 00000000..7e1636f9
--- /dev/null
+++ b/chapter31/docs/graphics.md
@@ -0,0 +1,109 @@
+# Optional graphics
+
+Simple owns the pixel array and drawing code. [MiniFB](https://github.com/emoon/minifb)
+provides a window, input, and pixel presentation. The first interface is
+`sys.gfx`: one fixed-size window, operated on the main thread. The
+[Graphics example](examples/Graphics.smp) draws a color gradient in Simple.
+
+## Default: no graphics dependency
+
+From `chapter31`, the usual `make release`, `make tests`, and `make tictactoe`
+need no MiniFB, graphics headers, OpenGL, CMake, or running display. Nothing
+downloads MiniFB unless you explicitly request `make graphics`.
+
+`make tests_nographics CTAGS=` runs the entire ordinary suite with
+`SIMPLE_MINIFB=off`. This includes the missing-backend tests, which never open
+windows. It excludes the interactive `run-graphics` target.
+
+The runtime contains a small loader using the OS dynamic-library facilities.
+It does nothing until `sys.gfx.open`. Without a configured backend, `open`
+prints a diagnostic to stderr and returns `sys.gfx.ERROR` (-1). Programs can
+return a nonzero status or fall back to text; the library does not terminate
+the process. Non-graphics programs ignore even a broken graphics configuration.
+
+## Build the optional backend
+
+From `chapter31`:
+
+```sh
+make graphics graphics-example CTAGS=
+make run-graphics CTAGS=
+```
+
+`graphics` downloads the revision pinned in [graphics.mk](../graphics.mk) into
+ignored `build/deps/minifb` and builds only its C framebuffer backend. Windows
+uses the MinGW-w64 GCC compiler (`x86_64-w64-mingw32-gcc`) and GDI; the rest of
+Simple still uses the existing Cygwin GCC. Linux uses GCC and X11 (`libx11-dev`
+on Ubuntu), including XWayland on a Wayland desktop. OpenGL, the C++ callback
+wrappers, and upstream example programs are omitted. Native Wayland and macOS
+builds are not provided here yet.
+
+Outputs:
+
+| Platform | Backend | Example |
+| --- | --- | --- |
+| Windows | `build/release/x86_64_v2_win64/simple_minifb.dll` | `build/examples/x86_64_v2_win64/Graphics.exe` |
+| Linux | `build/release/x86_64_v2_SystemV/libsimple_minifb.so` | `build/examples/x86_64_v2_SystemV/Graphics` |
+
+`MiniFB-LICENSE` is copied alongside the backend; include it when distributing
+the library. MiniFB sources remain outside the tracked Simple sources.
+
+`graphics-example` alone builds the executable without requiring MiniFB. It
+also demonstrates the diagnostic and exit status 1 when graphics is absent.
+`run-graphics` builds both, sets the backend path, and opens a window. Close it
+or release Escape to exit. Passing any argument to the executable makes it
+close after five polling iterations, for a quick smoke test.
+
+To run directly from PowerShell:
+
+```powershell
+$env:SIMPLE_MINIFB = (Resolve-Path build/release/x86_64_v2_win64/simple_minifb.dll).Path
+.\build\examples\x86_64_v2_win64\Graphics.exe
+```
+
+From Cygwin bash:
+
+```sh
+export SIMPLE_MINIFB="$PWD/build/release/x86_64_v2_win64/simple_minifb.dll"
+./build/examples/x86_64_v2_win64/Graphics.exe
+```
+
+For WSL, from the repository root:
+
+```sh
+wsl -d Ubuntu-24.04 -- bash -lc 'cd chapter31 && make graphics graphics-example CLZDIR=build/classes-linux CTAGS='
+```
+
+Inside WSL, set `SIMPLE_MINIFB` to the full path of the Linux `.so`, then run
+the Linux example with a working X11 display. For an automated virtual display:
+
+```sh
+SIMPLE_MINIFB="$PWD/build/release/x86_64_v2_SystemV/libsimple_minifb.so" \
+ xvfb-run -a build/examples/x86_64_v2_SystemV/Graphics smoke
+```
+
+The backend path is explicit: a DLL installed elsewhere or a different working
+directory cannot silently select the wrong version. `SIMPLE_MINIFB=off` disables
+graphics; an absent, unloadable, or incompatible backend produces a diagnostic.
+A backend that loads but cannot create a window also reports an error cleanly.
+
+## Initial interface
+
+| Operation | Meaning |
+| --- | --- |
+| `open(title,width,height)` | Open one window; returns `OK` or `ERROR`. |
+| `present(pixels)` | Present a `u32[~]` of exactly `width*height` pixels, packed `0x00RRGGBB`. |
+| `poll(wait)` | Process input; `true` waits about 17ms first to avoid a busy loop. |
+| `mouseX()`, `mouseY()` | Current mouse position, origin at upper left. |
+| `button(LEFT)`, `key(code)` | Current pressed state; printable keys use uppercase ASCII. |
+| `close()` | Release native window and pixel storage; safe to repeat. |
+
+`present` and `poll` return `OK` (0), `CLOSED` (1, normal close/Escape), or
+`ERROR` (-1). Stop polling after either terminal result and call `close`.
+The initial input API samples held state; it is not a queue of every transition.
+
+MiniFB retains its last framebuffer for repaint events. The adapter copies the
+Simple array into native-owned storage before presenting; it never retains a
+Simple heap pointer. Framebuffer allocation, the copy, and window/input calls
+are the only native work here. Drawing primitives and the games can be built
+in Simple on top of this boundary.