diff --git a/.claude/memory/schunix-crash-screen.md b/.claude/memory/schunix-crash-screen.md
index 686925d..2e56600 100644
--- a/.claude/memory/schunix-crash-screen.md
+++ b/.claude/memory/schunix-crash-screen.md
@@ -55,3 +55,27 @@ only ever seen when something is already wrong, and it quietly rots.
The serial copy is the one that survives, and it is what `tools/bootcheck.ps1`
reads. It is also all you get when the panic happens before there is a
framebuffer. See [[schunix-verify-by-driving-shell]].
+
+
+## 2026-09-21: the face is gone, and a bug it exposed
+
+PSOGM draws **Shift**, the system logo, where the Guru face used to be —
+`gfx_draw_logo()` from `include/logo.h`, the same mask the loader splash and
+the boot console use, at its native 128 px. `draw_guru()` and its geometry
+constants are deleted; so are `docs/branding/guru.svg` and the mascot brief.
+The *name* "Purple Screen of Guru Meditation" stays — that is the Amiga nod,
+which was always a separate thing from the mark.
+
+Taking the screenshot to check it caught a real regression from the TTF
+console work: **`gfx_draw_char()` still indexed the 8x16 bitmap with the
+TrueType cell height.** `font_data` has 16 rows per glyph and `CHAR_HEIGHT`
+became ~21, so every line of PSOGM drew five rows of the *next character's*
+bitmap underneath itself — it looked like each line had been printed twice.
+The grid path (`gfx_draw_cell`) had been updated; this one had not, because
+nothing routine draws pixel-positioned text. Both now go through one
+`draw_glyph_px()`, and the bitmap's own geometry is spelled `BITMAP_W/H` so it
+cannot be confused with a cell size again.
+
+**A crash screen is only checked by looking at it**, and nothing else in the
+system exercises `gfx_text_at`. Screenshot it after any font or console change:
+`echo c > /proc/sysrq`, then a QEMU monitor `screendump`.
diff --git a/docs/README.md b/docs/README.md
index c80ca3e..ebd0843 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -109,7 +109,7 @@ good chance it is in there.
| | |
|---|---|
-| [README](branding/README.md) | Shift the logo, Guru the icon, SchCotie the mascot: what each is for, the colour rule, and why a raster is committed next to its SVG. |
+| [README](branding/README.md) | Shift, the one mark: what it is for, the colour rule, why an icon and a mascot were removed, and why a raster is committed next to its SVG. |
## history/ — why it is the way it is
diff --git a/docs/Website/Assets/guru.svg b/docs/Website/Assets/guru.svg
deleted file mode 100644
index a9d4ed4..0000000
--- a/docs/Website/Assets/guru.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/docs/Website/README.md b/docs/Website/README.md
index cd286b3..05931a9 100644
--- a/docs/Website/README.md
+++ b/docs/Website/README.md
@@ -11,7 +11,7 @@ docs.html the documentation reader
style.css the palette, transcribed from include/theme.h
app.js the front page: the boot log types, sections fade in
docs.js the Markdown renderer and the doc index
-Assets/ shift.svg (logo), uberblock.svg (SchFS), guru.svg (PSOGM),
+Assets/ shift.svg (logo), uberblock.svg (SchFS),
usb.svg (downloads), pride.svg
```
diff --git a/docs/Website/index.html b/docs/Website/index.html
index 7b8e43e..a0e9c45 100644
--- a/docs/Website/index.html
+++ b/docs/Website/index.html
@@ -358,7 +358,7 @@
-
+
When it stops
PSOGM
diff --git a/docs/Website/style.css b/docs/Website/style.css
index e493ff3..a12b65c 100644
--- a/docs/Website/style.css
+++ b/docs/Website/style.css
@@ -326,7 +326,16 @@ header.top {
align-items: start;
}
@media (max-width: 44rem) { .crash .wrap { grid-template-columns: 1fr; } }
-.crash img { width: 100%; max-width: 8rem; height: auto; }
+/* Flat white, not the logo's own violets. This is what the kernel actually
+ draws: PSOGM composites the coverage mask in one colour, so a full-colour
+ mark here would show something the crash screen never shows -- and those
+ violets are close enough to this purple to half-disappear against it. */
+.crash img {
+ width: 100%;
+ max-width: 8rem;
+ height: auto;
+ filter: brightness(0) invert(1);
+}
.crash .eyebrow { color: #C3AEEC; }
.crash h2 { color: #fff; }
.crash p { color: #DBCEF5; }
diff --git a/docs/architecture/graphics.md b/docs/architecture/graphics.md
index 9c22bbf..429b1f6 100644
--- a/docs/architecture/graphics.md
+++ b/docs/architecture/graphics.md
@@ -198,14 +198,22 @@ matter more than the feature:
`kernel/core/panic.c`. The Purple Screen of Guru Meditation. Built around three
decisions:
-**It does not clear the screen.** Whatever was displayed stays, dimmed and
-pushed back, with the report floating over it. A crash screen that wipes the
-display tells you the machine is gone; one that leaves your work visible tells
-you it stopped — which is both truer and much less alarming.
+**It takes the whole screen.** It used to dim what was there and float a panel
+over it, on the argument that a crash screen which wipes the display tells you
+the machine is gone while one that leaves your work visible tells you it
+stopped. That looked good and was wrong: the thing is called a Purple Screen,
+and half a screen of abandoned work behind the report is a distraction at the
+worst possible moment.
-**It is not frightening.** No red, no capitals, no "FATAL". A calm sentence, a
-face that is obviously a cartoon, then the facts. Whoever is reading this is
-already having a bad time.
+**It is not frightening.** No red, no capitals, no "FATAL". A calm sentence,
+the Shift mark — the same one the machine drew on the splash it started with —
+then the facts. Whoever is reading this is already having a bad time.
+
+The mark replaced **Guru**, a chamfered face drawn from primitives that lived
+only here. Guru's argument was identity: `:(` is recognisably Microsoft's, and
+a crash screen is the screenshot most likely to leave the machine. That holds.
+What does not follow is that the answer is a *second* mark — see
+[../branding/README.md](../branding/README.md).
**It says considerably more than it needs to.** Everything cheap to collect is
collected: stop code, fault address, which CPU, which process, how far into the
diff --git a/docs/branding/README.md b/docs/branding/README.md
index 1626ef7..286691b 100644
--- a/docs/branding/README.md
+++ b/docs/branding/README.md
@@ -1,18 +1,29 @@
# Branding
-Three marks, three different jobs. They are not interchangeable and the
-difference is not stylistic.
+One mark.
| | | |
|---|---|---|
| **Shift** | *the logo* | An abstract mark. Non-human, non-animal. Signs the system. |
-| **Guru** | *the icon* | A pictogram. Denotes one state. Has a face; has no body. |
-| **SchCotie** | *the mascot* | A character. Has a body, poses and expressions. |
-The distinction that decides everything else: **a mascot has to be able to
-do things.** An icon works once, at one size, in one state. A character has to
-work confused, pleased, asleep and from behind — which is why it costs more and
-why it is drawn last.
+There were three. **Guru**, an icon — a pictogram with a face, denoting one
+state — lived on the crash screen and nowhere else. **SchCotie**, a mascot —
+a character with a body, poses and expressions — was a brief and was never
+drawn. Both are gone for now, and may come back.
+
+The reasoning that retired Guru is worth keeping, because it is the argument
+against any second mark. Guru existed to give the crash screen an identity:
+`:(` is recognisably Microsoft's, and a crash screen is the single screenshot
+most likely to leave the machine, so it is the worst place to be wearing
+somebody else's face. That part holds. What does not follow is that the answer
+is a *new* mark. Shift already signs the system, it is already what the machine
+drew on the splash it started with, and a reader who has seen it twice before
+the crash recognises it faster than a face they have never seen.
+
+SchCotie went for a simpler reason: **a mascot has to be able to do things.**
+An icon works once, at one size, in one state. A character has to work
+confused, pleased, asleep and from behind — which is why it costs more, and why
+a brief for one is not worth carrying until somebody is going to draw it.
---
@@ -46,61 +57,8 @@ the kernel's name (**SchIFT**) as a shape.
- **With or without a wordmark.** Set "SchOS" beside it in **Roboto Bold**,
which is already in the tree (`ports/Roboto`), already Apache-2.0, and already
in `NOTICE`.
-- Non-human and non-animal, permanently. The character work belongs to
- SchCotie; a logo that starts growing a face has taken the mascot's job.
-
-## Guru — the icon
-
-`guru.svg`
-
-The crash face. Mythic rather than cartoon — closer to a temple carving than a
-character — square or nearly so, with an expression that stays in the
-`:(` / `:|` register.
-
-**Purple, and only purple, and only here.** `theme.h` states the rule it
-enforces:
-
-> normal states are calm and dark; only failure is loud. PSOGM keeps the
-> full-bleed purple entirely to itself, which is what makes it mean something.
-
-That purple is `PSOGM_BG #4B1D9A`, and it is deliberately **not** the accent
-`#7C5CFF`. If Guru ever appears in accent violet on a splash, a sticker or a
-README header, the deep purple stops meaning *the machine stopped* — and it is
-the only colour in the system that means anything at all.
-
-So: Guru does not leave the crash screen.
-
-## SchCotie — the mascot
-
-*Not drawn yet.*
-
-A daemon: **the process that works while nobody is watching.** The horns are a
-pun on the word; the meaning is the background job that keeps running after you
-have walked away — which is `schinit` supervising, restarting what dies, awake
-at 3am. Patient and watchful rather than mischievous.
-
-Horns carry **X** — POSIX, Unix, X11 — one substitution reading three ways.
-
-Two constraints that follow from the section above. A thin X is two diagonal
-strokes and dissolves at small sizes, so it wants to be **solid wedges with the
-X notched out as negative space**: the horn silhouette survives downscaling and
-the X appears as you get closer. And it needs a **turnaround** — front, side,
-three-quarter, matching heights on shared construction lines — because a
-character drawn once at one angle only ever works at that angle.
-
-### The licensing point, which is not optional here
-
-**The BSD daemon is copyrighted.** Marshall Kirk McKusick holds it and the terms
-are not a free licence. A character that reads as "Beastie, but purple, with X
-horns" is a derivative-work argument, and this mark would be in every image
-SchOS ships, beside a `NOTICE` file this project has been careful about.
-
-The concept is not the problem. A daemon is a Greek *daimon* and a Unix
-background process — neither is ownable. What belongs to Beastie is the
-execution: the pitchfork, the sneakers, that red, that face, that pose. Horns, a
-tail and a small imp are generic and thousands of years old.
-
-**Draw from the idea. Do not have a picture of Beastie open while you do it.**
+- Non-human and non-animal, permanently. If a character is ever drawn it gets
+ its own mark; a logo that starts growing a face has taken that job.
---
@@ -114,8 +72,18 @@ value it does not already define.
| `SCH_BG` | `#0C0E13` | Ground. Near-black with a blue cast, because pure black reads as "switched off". |
| `SCH_FG` | `#E6E8EC` | Primary text |
| `SCH_DIM` | `#707784` | Secondary |
-| `SCH_ACCENT` | `#7C5CFF` | The one accent. Shift, SchCotie, anything calm. |
-| `PSOGM_BG` | `#4B1D9A` | **Failure only.** Guru's ground and nothing else's. |
+| `SCH_ACCENT` | `#7C5CFF` | The one accent. Shift, and anything calm. |
+| `PSOGM_BG` | `#4B1D9A` | **Failure only.** The crash screen's ground and nothing else's. |
+
+`PSOGM_BG` is deliberately **not** the accent. `theme.h` states the rule it
+enforces:
+
+> normal states are calm and dark; only failure is loud. PSOGM keeps the
+> full-bleed purple entirely to itself, which is what makes it mean something.
+
+If that purple ever appears on a splash, a sticker or a README header, it stops
+meaning *the machine stopped* — and it is the only colour in the system that
+means anything at all.
## File formats
@@ -154,7 +122,6 @@ shift.svg the logo, in colour
shift-mask.svg the same geometry in greys -- see below
shift-mask.png rasterised from it, committed on purpose
uberblock.svg SchFS
-guru.svg the crash icon
superseded-*.png the old wordmark, kept for reference only
```
@@ -189,8 +156,8 @@ If either is edited, edit both.
|---|---|
| Loader splash | Shift, from `include/logo.h`, shaded per row by `metal()` in `boot/common/ui.c` — silver, not accent. |
| Kernel console / early boot | Shift, same mask, composited flat in a theme colour by `gfx_draw_logo`. |
-| PSOGM | Guru, drawn from primitives by `draw_guru()` in `kernel/core/panic.c`. Never a bitmap: it scales with the display and costs nothing in the kernel image. |
-| Serial crash report | `:(`, as text. Guru cannot be drawn in ASCII, and a mood marker in a log is not the icon. |
+| PSOGM | Shift, the same mask again, by `gfx_draw_logo()` from `kernel/core/panic.c`. At its native 128 px — there is no resampler in the crash path, and the mark was only ever drawn at one size there anyway. |
+| Serial crash report | `:(`, as text. The mark cannot be drawn in ASCII, and a mood marker in a log is not a mark. |
| SchFS | **Nowhere yet.** `uberblock.svg` has no consumer; it is waiting for `projects/schfs-linux/` to have a README worth heading. |
One trap, since it has already been stepped in: `boot/common/ui.c` includes
@@ -207,10 +174,8 @@ loader must actually relink**, and that needs `clang` and `lld-link`.
has registered or defended.
- **No usage rules for third parties** — nothing says what someone else may do
with them. Worth writing before anything is published.
-- **SchCotie does not exist.** Everything above it is a brief, not a
- description.
-- **Guru is drawn but not wired in.** `panic.c` still renders `:(` from
- primitives, and there is a real argument for keeping it — see the note in that
- file about being "legible as a mood without being a picture of anything".
+- **There is no icon and no mascot.** Both were removed rather than left
+ half-specified. If either comes back it starts from the argument at the top
+ of this file, not from what used to be here.
- **No wordmark lockup is specified.** "Roboto Bold beside it" is not a spacing
rule, a size ratio or a clear-space margin, and it will want to be.
diff --git a/docs/branding/guru.svg b/docs/branding/guru.svg
deleted file mode 100644
index a9d4ed4..0000000
--- a/docs/branding/guru.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/kernel/core/panic.c b/kernel/core/panic.c
index 63c01f4..ab77b6e 100644
--- a/kernel/core/panic.c
+++ b/kernel/core/panic.c
@@ -5,15 +5,16 @@
// The name is a nod to the Amiga's "Guru Meditation", but nothing else about
// this is a nod to 1985. Three things it is built around:
//
-// *It does not clear the screen.* Whatever was being displayed stays there,
-// dimmed and pushed back, with the report floating over it. A crash screen that
-// wipes the display tells you the machine is gone; one that leaves your work
-// visible underneath tells you it stopped, which is both truer and much less
-// alarming.
+// *It takes the whole screen.* An earlier version dimmed what was there and
+// floated a panel over it, on the argument that a crash screen which wipes the
+// display tells you the machine is gone while one that leaves your work visible
+// tells you it stopped. That looked good and was wrong: the thing is called a
+// Purple Screen, and half a screen of somebody's abandoned work behind the
+// report is a distraction at the worst possible moment.
//
-// *It is not frightening.* No red, no capitals, no "FATAL". A calm sentence, a
-// face that is obviously a cartoon, and then the facts. Whoever is reading this
-// is already having a bad time.
+// *It is not frightening.* No red, no capitals, no "FATAL". A calm sentence,
+// the system's own mark, and then the facts. Whoever is reading this is
+// already having a bad time.
//
// *It says considerably more than it needs to.* The screen is the only artefact
// of a kernel panic — there is no core dump and no log to go back to — so
@@ -40,6 +41,7 @@
// same names but with different values, which meant theme.h described a crash
// screen nobody had ever seen.
#include "theme.h"
+#include "logo.h" /* LOGO_H -- the mark's height, for the layout below */
#include "qr.h"
extern uint ticks;
@@ -87,80 +89,6 @@ put_hex(char *p, char *end, uint64 v, int digits)
return p;
}
-/* ------------------------------------------------------------------ */
-/* The face */
-/* */
-/* Guru: a chamfered head with two eyes and a flat mouth. See */
-/* docs/branding/ -- it is the system's icon, and the only place it is */
-/* allowed to appear is here. */
-/* */
-/* This replaced ":(", two dots and a parenthesis, whose argument was */
-/* that it is "legible as a mood without being a picture of anything, */
-/* and does not pretend the machine has feelings about what just */
-/* happened." That reasoning was good and is recorded because it is */
-/* the thing being traded away: a face is a louder claim than a */
-/* punctuation mark, and it has to earn the volume. */
-/* */
-/* What it buys is identity. ":(" is Microsoft's, recognisably, and a */
-/* crash screen is the single screenshot most likely to leave the */
-/* machine -- so it is the worst place to be wearing somebody else's */
-/* face. The octagon also quotes the chamfered corners of the old */
-/* SchOS letterforms, which is the only part of that mark still in use. */
-/* */
-/* Still drawn from primitives rather than stored as a bitmap, for the */
-/* original reason: it scales with the display and costs no space in a */
-/* kernel image. Two rectangles and a run of spans -- no allocation, no */
-/* locks, nothing that can fail halfway. */
-/* ------------------------------------------------------------------ */
-
-/* Geometry, in the 200-unit box docs/branding/guru.svg is drawn in, so the
- * two cannot drift apart without somebody editing a number here on purpose.
- * The head spans 24..176 of that box; everything is expressed against it. */
-#define GURU_BOX_LO 24 /* head's left/top edge in the SVG box */
-#define GURU_BOX_SPAN 152 /* head's width and height there */
-#define GURU_CHAMFER 34 /* corner cut */
-
-/* SVG coordinate -> pixel offset within a head `h` tall. */
-static int
-gmap(int v, int h)
-{
- return (v - GURU_BOX_LO) * h / GURU_BOX_SPAN;
-}
-
-static void
-draw_guru(int x, int y, int h, uint32 color, uint32 bg)
-{
- /* The head, as horizontal spans. A scanline fill rather than a polygon
- * routine: the shape is convex and its left edge is one subtraction, so
- * this is the whole of it. */
- for (int py = 0; py < h; py++) {
- int sy = GURU_BOX_LO + py * GURU_BOX_SPAN / h; /* back to SVG space */
- int inset = 0;
- if (sy < GURU_BOX_LO + GURU_CHAMFER)
- inset = (GURU_BOX_LO + GURU_CHAMFER) - sy;
- else if (sy > GURU_BOX_LO + GURU_BOX_SPAN - GURU_CHAMFER)
- inset = sy - (GURU_BOX_LO + GURU_BOX_SPAN - GURU_CHAMFER);
-
- int x0 = gmap(GURU_BOX_LO + inset, h);
- int x1 = gmap(GURU_BOX_LO + GURU_BOX_SPAN - inset, h);
- if (x1 > x0)
- gfx_fill_rect(x + x0, y + py, x1 - x0, 1, color);
- }
-
- /* The eyes and the mouth are knocked out of the head rather than drawn on
- * top of it, which is what keeps them legible when the head is small: a
- * hole in a solid reads at sizes a stroke does not. */
- int ey = gmap(82, h), eh = gmap(104, h) - gmap(82, h);
- int e1x = gmap(74, h), e2x = gmap(110, h);
- int ew = gmap(90, h) - gmap(74, h);
- gfx_fill_rect(x + e1x, y + ey, ew, eh, bg);
- gfx_fill_rect(x + e2x, y + ey, ew, eh, bg);
-
- int mx = gmap(72, h), mw = gmap(128, h) - gmap(72, h);
- int my = gmap(128, h), mh = gmap(139, h) - gmap(128, h);
- gfx_fill_rect(x + mx, y + my, mw, mh, bg);
-}
-
/* ------------------------------------------------------------------ */
/* The report */
/* ------------------------------------------------------------------ */
@@ -458,9 +386,24 @@ paint(char *reason, addr_t *pcs, int npcs)
if (left > 110) left = 110;
int y = sh / 8;
- int face_h = 96;
- draw_guru(left, y, face_h, PSOGM_FG, PSOGM_BG);
- y += face_h + ch * 2;
+ // Shift, the system's own mark, from the same include/logo.h the loader
+ // splash and the boot console draw. It replaces Guru, a chamfered face that
+ // lived only here and was drawn from primitives a few lines up this file.
+ //
+ // Guru was an *icon*: a pictogram denoting one state, with a face. The
+ // argument for it was identity -- ":(" is recognisably Microsoft's, and a
+ // crash screen is the single screenshot most likely to leave the machine, so
+ // it is the worst place to be wearing somebody else's face. That argument
+ // holds. It just does not follow that the answer is a second mark. The logo
+ // already signs the system, it is already the thing on the splash the
+ // machine started with, and a reader who has seen it twice before the crash
+ // recognises it faster than a face they have never seen.
+ //
+ // A fixed 128 px rather than scaled: the mask is 128x128 and there is no
+ // resampler here. The face was scalable and that bought nothing -- it was
+ // drawn at one size.
+ gfx_draw_logo(left, y, PSOGM_FG, PSOGM_BG);
+ y += LOGO_H + ch * 2;
// Left-aligned, not centred. Centred text reads as a poster; this is a
// report, and a report is read down the left edge.
diff --git a/kernel/dev/gfx.c b/kernel/dev/gfx.c
index 215792b..0409bd5 100644
--- a/kernel/dev/gfx.c
+++ b/kernel/dev/gfx.c
@@ -39,8 +39,16 @@
// its own metrics. These start at the bitmap's size because the console has to
// work from the first panic onwards -- before gfx_font_init() has run there is
// no font, and 8x16 against font_data is exactly what there always was.
-static int cell_w = 8;
-static int cell_h = 16;
+// The bitmap's own geometry, which is fixed forever: font_data is
+// `uchar[256][16]` and each row is eight bits. Naming it separately from the
+// cell size is not pedantry -- the two were the same number, then one of them
+// started moving, and the code that kept indexing font_data by the moving one
+// read straight off the end of every glyph.
+#define BITMAP_W 8
+#define BITMAP_H 16
+
+static int cell_w = BITMAP_W;
+static int cell_h = BITMAP_H;
#define CHAR_WIDTH cell_w
#define CHAR_HEIGHT cell_h
@@ -52,6 +60,7 @@ static struct font *cfont;
static int cfont_baseline;
static uint32 blend(uint32 bg, uint32 fg, uint a);
+static void draw_glyph_px(int x, int y, uint32 cp, uint32 fg, uint32 bg);
// The scanout, as published by whichever driver owns the display. Zeroed until
// one does, and every entry point checks `fb` before touching memory -- a
@@ -141,20 +150,10 @@ gfx_clear(uint32 color)
void
gfx_draw_char(int x, int y, uchar c, uint32 color)
{
- // No `c > 127` rejection any more: font_data holds 256 Latin-1 glyphs, and
- // a uchar cannot index past them.
- if (!fb) return;
-
- for (int row = 0; row < CHAR_HEIGHT; row++) {
- uchar row_data = font_data[c][row];
- for (int col = 0; col < CHAR_WIDTH; col++) {
- if (row_data & (0x80 >> col)) {
- gfx_draw_pixel(x + col, y + row, color);
- } else {
- gfx_draw_pixel(x + col, y + row, gfx_bg);
- }
- }
- }
+ // Pixel-positioned rather than on the grid -- the crash screen lays itself
+ // out in pixels because it is a report, not a terminal. Same glyph path as
+ // the grid uses, which it did not used to be; see draw_glyph_px().
+ draw_glyph_px(x, y, c, color, gfx_bg);
}
void
@@ -246,13 +245,21 @@ gfx_putc(int c, uint32 color)
// gfx_draw_char paints its background from the file-static gfx_bg, which is
// right for a console that has one background and wrong for a terminal where
// every cell carries its own.
-void
-gfx_draw_cell(int col, int row, uint32 cp, uint32 fg, uint32 bg)
+// One glyph, at a pixel position, in a cell-sized box.
+//
+// Both the console grid and the pixel-positioned text in the crash screen come
+// through here, which is the point: they used to be two implementations, and
+// only one of them was updated when the cell size stopped being 8x16.
+// gfx_draw_char() still walked `font_data[c][row]` for `row < CHAR_HEIGHT` --
+// and CHAR_HEIGHT is the *TrueType* cell height now, while font_data has
+// exactly 16 rows per glyph. Every line of PSOGM therefore drew five rows of
+// the *next character's* bitmap underneath itself. It looked like each line
+// had been printed twice.
+static void
+draw_glyph_px(int x, int y, uint32 cp, uint32 fg, uint32 bg)
{
if (!fb)
return;
-
- int x = col * cell_w, y = row * cell_h;
if (x < 0 || y < 0 ||
x + cell_w > (int)scanout.width || y + cell_h > (int)scanout.height)
return;
@@ -261,11 +268,15 @@ gfx_draw_cell(int col, int row, uint32 cp, uint32 fg, uint32 bg)
// drawn as a space rather than as the wrong glyph -- `?` was at least honest
// about being a substitute, and a CP437 picture of something unrelated is
// not.
+ //
+ // BITMAP_W/H and not cell_w/h: the bitmap's geometry is a property of
+ // font_data, not of whatever the console decided a cell is. They agree
+ // whenever cfont is null, and the assert below is what keeps that true.
if (!cfont) {
uchar g = cp < 256 ? (uchar)cp : ' ';
- for (int r = 0; r < cell_h; r++) {
+ for (int r = 0; r < BITMAP_H; r++) {
uchar bits = font_data[g][r];
- for (int c = 0; c < cell_w; c++)
+ for (int c = 0; c < BITMAP_W; c++)
gfx_draw_pixel(x + c, y + r, (bits & (0x80 >> c)) ? fg : bg);
}
return;
@@ -303,6 +314,12 @@ gfx_draw_cell(int col, int row, uint32 cp, uint32 fg, uint32 bg)
}
}
+void
+gfx_draw_cell(int col, int row, uint32 cp, uint32 fg, uint32 bg)
+{
+ draw_glyph_px(col * cell_w, row * cell_h, cp, fg, bg);
+}
+
// Bring the console typeface up. Called once, early, from the display path.
//
// The font is linked into the kernel (see CONSFONT in the Makefile) because