gfx: Guru on the crash screen, and the loader rebuilds when the logo changes
PSOGM drew ":(" -- two dots and a parenthesis. It now draws Guru, the icon from
docs/branding/: a chamfered head with two eye knockouts and a flat mouth, in the
:| register.
The old reasoning is kept in the file rather than deleted, because it is the
thing being traded away: ":(" was "legible as a mood without being a picture of
anything, and does not pretend the machine has feelings about what just
happened." That is a real argument and a face is a louder claim. What it buys is
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. 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, for the original reason: it scales with the display
and costs no space in the kernel image. A scanline fill for the head, two
rectangles and one more knocked out of it -- no allocation, no locks, nothing
that can fail halfway, which is the whole constraint of panic context. The
geometry is expressed in the same 200-unit box docs/branding/guru.svg uses so
the two cannot drift without somebody editing a number on purpose.
The eyes and mouth are knocked out of the head rather than drawn on top of it,
which is what keeps them legible small: a hole in a solid reads at sizes a
stroke does not.
Verified by crashing on purpose -- echo c > /proc/sysrq -- and screendumping the
framebuffer through the QEMU monitor. The serial report still says ":(", and
should: Guru cannot be drawn in ASCII, and a mood marker in a log is not the
icon.
Separately, and found by looking at the boot splash rather than at the code:
boot/common/ui.c includes logo.h, theme.h and font.h, and the Makefile rule for
the loader listed none of them. A new logo therefore did not rebuild the loader.
The splash had been drawing a mask compiled six hours earlier while `make`
reported nothing to do, and the only symptom was a boot screen quietly
disagreeing with the kernel about what the logo is. The kernel half never showed
it because those objects are built with -MD -MP and track their own headers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
parent
d73985633b
commit
c4d4f20548
3 changed files with 85 additions and 48 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue