diff --git a/Makefile b/Makefile index 27cb7a9..25ec4b6 100644 --- a/Makefile +++ b/Makefile @@ -471,8 +471,15 @@ kernel: $(BUILD)/kernel/kernel # ----------------------------------------------------------------------- UEFI_CFLAGS = --target=x86_64-unknown-windows -ffreestanding -fshort-wchar -mno-red-zone -fno-stack-protector -Wall -Wextra -O1 -I./include +# The three headers at the end are the ones boot/common/ui.c actually includes, +# and leaving them out meant a new logo did not rebuild the loader: the splash +# kept drawing whatever mask was compiled in months earlier, `make` reported +# nothing to do, and the only symptom was a boot screen that disagreed with the +# kernel about what the logo is. The kernel half never showed it because those +# objects are built with -MD -MP and pick up header changes on their own. $(BUILD)/uefi/BOOTX64.EFI: boot/uefi/main.c boot/uefi/efi.h include/schboot.h \ - boot/common/ui.c boot/common/ui.h + boot/common/ui.c boot/common/ui.h \ + include/logo.h include/theme.h include/font.h @mkdir -p $(BUILD)/uefi clang $(UEFI_CFLAGS) -c boot/uefi/main.c -o $(BUILD)/uefi/main.obj clang $(UEFI_CFLAGS) -c boot/common/ui.c -o $(BUILD)/uefi/ui.obj diff --git a/docs/branding/README.md b/docs/branding/README.md index c498293..0f86089 100644 --- a/docs/branding/README.md +++ b/docs/branding/README.md @@ -164,6 +164,24 @@ If either is edited, edit both. --- +## Where each mark is actually drawn + +| | | +|---|---| +| 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. | +| 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 +`logo.h`, `theme.h` and `font.h`, and the Makefile rule for the loader did not +list them. A new logo therefore did not rebuild the loader — `make` reported +nothing to do and the splash kept drawing a mask compiled months earlier. The +kernel half never showed the problem because those objects are built with +`-MD -MP` and track their own headers. **Changing anything in here means the +loader must actually relink**, and that needs `clang` and `lld-link`. + ## What this does not cover - **No trademark position.** These are marks the project uses, not marks anyone diff --git a/kernel/core/panic.c b/kernel/core/panic.c index 75588bc..28df9b9 100644 --- a/kernel/core/panic.c +++ b/kernel/core/panic.c @@ -90,63 +90,75 @@ put_hex(char *p, char *end, uint64 v, int digits) /* ------------------------------------------------------------------ */ /* The face */ /* */ -/* ":(" — two dots and a parenthesis, drawn large. It is a sad face */ -/* only if you tilt your head, which is exactly why it works: it is */ -/* legible as a mood without being a picture of anything, and it does */ -/* not pretend the machine has feelings about what just happened. */ +/* 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. */ /* */ -/* Drawn from primitives rather than stored as a bitmap, so it scales */ -/* with the display and costs no space in a kernel image that stage2 */ -/* loads one sector at a time by PIO. */ +/* 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 -isqrt(int v) +gmap(int v, int h) { - if (v <= 0) - return 0; - - // Newton's method, iterated only while the estimate is still *decreasing*. - // - // The obvious "stop when it stops changing" version does not terminate: on a - // non-square it settles into a two-cycle rather than a fixed point, and - // isqrt(3) alternates between 1 and 2 forever. In a panic handler that is a - // hang with the screen half drawn and no way to find out why. - int x = v; - int y = (x + 1) / 2; - while (y < x) { - x = y; - y = (x + v / x) / 2; - } - return x; -} - -// The "(" of ":(" — the left half of a squashed circle, so the tips point right -// and the middle bulges left, the way the glyph does. -static void -draw_paren(int cx, int cy, int h, int thick, uint32 color) -{ - int r = h / 2; - for (int dy = -r; dy <= r; dy++) { - int dx = isqrt(r * r - dy * dy); - // Narrow it: a true half-circle reads as a bracket, not a parenthesis. - int x = cx - (dx * 45) / 100; - gfx_fill_circle(x, cy + dy, thick / 2, color); - } + return (v - GURU_BOX_LO) * h / GURU_BOX_SPAN; } static void -draw_sad_face(int x, int y, int h, uint32 color) +draw_guru(int x, int y, int h, uint32 color, uint32 bg) { - int dot = h / 12; - int gap = h / 4; + /* 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); - // The colon. - gfx_fill_circle(x + dot, y + h / 2 - gap, dot, color); - gfx_fill_circle(x + dot, y + h / 2 + gap, dot, color); + 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 parenthesis, a little to the right of it. - draw_paren(x + dot * 2 + h / 2, y + h / 2, h, dot * 2, 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); } /* ------------------------------------------------------------------ */ @@ -435,7 +447,7 @@ paint(char *reason, addr_t *pcs, int npcs) int y = sh / 8; int face_h = 96; - draw_sad_face(left, y, face_h, PSOGM_FG); + draw_guru(left, y, face_h, PSOGM_FG, PSOGM_BG); y += face_h + ch * 2; // Left-aligned, not centred. Centred text reads as a poster; this is a