luvcraft/balls.lisp
--------------------------------------------------------------------- Three tiles of the atlas: what a ball, a drop, and a gobbet are painted with.
A ball: worn red rubber with one pale band around it, so it is seen to turn.
Water: a clear cool blue with a lighter ripple through it.
Lava: near-white heat veined through orange; the glow is added per body.
--------------------------------------------------------------------- Body kinds: the game's palette of things a body can be. The physics keeps only the index; everything the eye or the game wants is here. The albedo and pattern feed the sphere pipeline's instance stream, so this vector stays the single source of truth for what a kind looks like; the tile survives for the hand item and the atlas painters.
The sphere fragment stage's number for a surface pattern.
The shader selects the procedural pattern by this lane, so the pairing is closed on both sides: a new pattern is a new shader arm and a new entry here, together.
The drawn sphere's radius as a fraction of the physics radius. One is the honest size; the constructor keeps the knob for a kind that wants to read smaller than it collides.
The base colour the shader patterns over, resolved here so *BODY-KINDS*
stays the palette's one authority.
The party kinds. The beach ball is big, light, and bouncy; the smiley ball is small, bouncier still, and wears its face in the pattern frame, so the grin tumbles as it bounces.
Add a body of the kind name to physics and return its handle.
--------------------------------------------------------------------- Drawing. The scene pass gets one 16-float instance record per body -- centre and radius, orientation quaternion, albedo and emission, sampled light and pattern -- for the sphere pipeline's camera-facing quads; the shadow pass still rasterizes each body as a small turning cube in the block pipeline's vertex format, which is cheap and correct for a depth map. Both streams are preallocated specialized arrays owned by one streams record in the session; displaced views of the filled parts are what the frame uploads. Because the sphere quads blend without writing depth, the instance records are handed over farthest-from-the-eye first, so a pile of balls occludes itself correctly.
The shadow cube's half-size as a fraction of the drawn sphere's radius: a touch under, toward the inscribed cube, so shadows do not read fat.
Thirty-six vertices of a unit cube about the origin: for each, the local corner (-0.5..0.5), the tile-local UV, and the face normal, flat.
The per-frame render products built from the physics columns.
INSTANCES holds the sphere records the scene pass draws, already ordered farthest first for the blend; SCRATCH holds them in storage order before the sort, with DEPTHS and ORDER as the sort's reusable working set. SHADOW-VERTICES holds the little cubes the shadow pass rasterizes, whose order no depth map cares about.
The session's PHYSICS-VERTEX-STREAM slot holds the whole streams record; its PHYSICS-VERTEX-COUNT slot holds the drawn body count.
Normalized sky and block light at a body's centre; open sky when absent.
Fill streams from physics's bodies and return how many were drawn.
One pass writes each body's sphere instance record into the scratch stream in storage order, its squared distance to the eye beside it, and its shadow cube's corners -- position lanes only; the shadow stage reads nothing else. The instance records are then dealt into the upload stream farthest first, because the scene pass blends them over each other without writing depth.
The rotation matrix of the unit quaternion, for the shadow cube's turned corners.
Farthest first for the blend. The displaced view is one small header per frame; SBCL sorts vectors in place.
How many bodies the last build of the session's streams drew.
The filled sphere instance records, farthest first, for the upload.
How many cube vertices the shadow pass draws for the bodies.
The filled part of the shadow cube stream, for the upload.
--------------------------------------------------------------------- The session's physics: made on first use, stepped at a fixed rate from the frame clock, fed the player and the animals as boxes, and asked afterwards what happened.
How many steps one frame may catch up; beyond that time is dropped, so a stall does not become a spiral.
Tell physics where the player and the animals are and how they move.
Something hit critter at X,Y,Z arriving at speed. Most animals ignore
it; a turtle takes it as a reason to go somewhere else.
Act on what the step found out.
Step the session's physics as many fixed steps as seconds owe, then
build this frame's sphere instance and shadow cube streams.
A frame that fell far behind forgets the rest rather than catching up forever.
--------------------------------------------------------------------- Springs: the fountain and the lava well. A spring is a coordinate the session found in its world's authored edits, or was told about when the player placed one; each physics step it may throw something, if its cell is resident and still holds a spring.
The (X Y Z KIND) of every spring block written into world's edits.
Rediscover the world's springs from its authored edits.
A stable 0..1 reading for spring's current throw and salt.
--------------------------------------------------------------------- The ball in the hand.
A ball to throw. The hand never runs out: each throw is a new body.
ball
Held low and to the right, a little forward, the way you carry a ball you mean to throw.
Small in the hand: the grip frame sits close to the eye.
Throw a body of kind from the player's eye along the view, nudged by
aim-right and aim-up; return its handle.
Every fifth ball out of the hand is a smiley: enough to be a delight, not so many that the ball stops being the ball.
A handful of marbles, scattered the same way from the same count.
Take the session's ball out, or put it away.
--------------------------------------------------------------------- The party: a burst of balls for a birthday.
Scatter a deterministic mix of beach balls, smiley balls, and classic
balls around center, each with a small pop-up velocity, and return their
handles, newest first.
center is an (X Y Z) list; without one the balls burst a few cells ahead
of the session's camera. The scatter is hashed, not random, so the same
call throws the same party.
--------------------------------------------------------------------- The knobs: what the metabar can turn on the physics.
--------------------------------------------------------------------- Reading the physics from the metabar.
Remove every ball, drop, and gobbet from the session's world.
A ball to throw. The hand never runs out: each throw is a new body.
(session &key center (count 20))Scatter a deterministic mix of beach balls, smiley balls, and classic balls around CENTER, each with a small pop-up velocity, and return their handles, newest first. CENTER is an (X Y Z) list; without one the balls burst a few cells ahead of the session's camera. The scatter is hashed, not random, so the same call…
(critter x y z speed)Something hit CRITTER at X,Y,Z arriving at SPEED. Most animals ignore it; a turtle takes it as a reason to go somewhere else.
(tile x y)Return the packed RGBA pixel of atlas tile TILE at tile-local X,Y. Each named tile is one EQL method, so a live image can repaint a single material and rebuild the atlas without touching the rest of the palette.
Test whether one compatible scalar is at most another.
(x y tile)(red green blue &optional (variation 0))(x y salt period)Subtraction or unary negation.
Test whether one compatible scalar is greater than another.
(pattern)The sphere fragment stage's number for a surface PATTERN. The shader selects the procedural pattern by this lane, so the pairing is closed on both sides: a new pattern is a new shader arm and a new entry here, together.
Convert one scalar float or unsigned value to a 32-bit float.
(name)Logical disjunction of tests and raw truth values.
(physics name x y z &key (vx 0.0) (vy 0.0) (vz 0.0)
lifetime)(world x y z &key (radius 0.25) (mass 1.0) (vx 0.0) (vy 0.0) (vz 0.0)
(restitution 0.3) (friction 0.5) (rolling-resistance 0.01)
(damping 0.05) (kind 0)
(collides-with-bodies-p t) (hit-report-p nil)
(never-sleep-p nil) (lifetime nil))The most bodies drawn in one frame; both streams are sized for it.
Cube vertices per body in the shadow stream.
Multiplication and scalar scaling.
Four vec4 lanes per body in the sphere instance stream.
The shadow cube's half-size as a fraction of the drawn sphere's radius: a touch under, toward the inscribed cube, so shadows do not read fat.
Thirty-six vertices of a unit cube about the origin: for each, the local corner (-0.5..0.5), the tile-local UV, and the face normal, flat.
(face corner)Project CORNER onto FACE's plane as tile-local UV coordinates. The rule is read from the face's own outward normal rather than its name: horizontal faces map world X,Z straight across the tile, and lateral faces keep the world-horizontal axis as U while flipping world Y into V so tiles hang upright.
Addition over compatible quantities.
(session)(world x y z)(world x y z)Division of two represented quantities.
(physics world streams eye-x eye-y eye-z)Fill STREAMS from PHYSICS's bodies and return how many were drawn. One pass writes each body's sphere instance record into the scratch stream in storage order, its squared distance to the eye beside it, and its shadow cube's corners -- position lanes only; the shadow stage reads nothing else. The instance records…
Headings, paragraphs, figures and their IDs, mentions, marks.
((bindings buffer buffer-type) &body body)Borrow BUFFER-TYPE's active extent, row declaration, and raw lane arrays. BINDINGS is (LENGTH ROW-DECLARATION (ARRAY LANE-NAME) ...). The buffer is evaluated once, and every array receives its precise specialized array type. This is the checked aggregate boundary for closed scalar or SIMD kernels; the kernel…
Test whether one compatible scalar is at least another.
(session)(session)How many steps one frame may catch up; beyond that time is dropped, so a stall does not become a spiral.
(session)(&key terrain (kernels :fastest))(session)(session physics)(world)(player)(player)(player)(world min-x min-y min-z max-x max-y max-z
&key (vx 0.0) (vy 0.0) (vz 0.0) owner)(player)(player)(player)One individuated animal walking the block world.
(critter)(critter)(critter)(critter)(critter)(critter)A small, slow, deliberate animal with a domed shell.
(turtle)(session physics)((kind handle-a handle-b owner x y z speed world) &body body)Logical conjunction of tests and raw truth values.
(session seconds)Step the session's physics as many fixed steps as SECONDS owe, then build this frame's sphere instance and shadow cube streams.
Test whether one compatible scalar is less than another.
(session physics)(world &optional dt)Advance WORLD by DT seconds (its step by default) and return it. Events from the step are then readable until the next step begins. #IDVK7G
A block that throws things: a fountain of water, a well of lava. What it throws is decided by its name in luvcraft/balls.lisp; the class is what lets placing and removing one be a method rather than a name test.
(block session x y z)BLOCK has just been put down at X,Y,Z by the player in SESSION. Most blocks are inert and the default does nothing; a block that does something where it stands -- a film beside a wall -- answers here.
(block session x y z)BLOCK has just been taken away from X,Y,Z by the player in SESSION.
Test whether two compatible scalars are equal.
(spring salt)(seed index salt)Return a stable 0..1 reading for one small animal choice. The same three integers always answer the same way, which is what lets a wandering animal be reproducible without carrying a random state around.
A lava spring spits one gobbet every this many steps.
(spring session physics)(world x y z)Return one site as BLOCK and :RESIDENT, or NIL and :ABSENT. This sparse world-coordinate accessor constructs coordinate descriptors and a chunk lookup key. It is appropriate for inspectors, ray hits, collision probes, and sparse interaction. Algorithms over many cells should select a chunk/domain once and use…
The non-negative remainder of integer division.
How fast a thrown ball leaves the hand, cells per second.
(item body)Where BODY holds ITEM: (X Y Z PITCH YAW ROLL) of the grip in the view frame, before walking bob is added.
(item body function)Call FUNCTION for each textured box of ITEM as held by BODY. FUNCTION receives (X Y Z HALF-X HALF-Y HALF-Z TILE &KEY TILT STRETCH-P EMISSION), like MAP-CRITTER-BOXES with three extras: TILT is a (PITCH YAW ROLL) triple of radians turning the box about its own centre, STRETCH-P stretches the whole atlas tile over each…
(session &key (speed *ball-throw-speed*) (kind :ball)
(aim-right 0d0) (aim-up 0d0))Throw a body of KIND from the player's eye along the view, nudged by AIM-RIGHT and AIM-UP; return its handle.
(camera)The componentwise square root of a raw value.
(item body session button)The player clicked BUTTON while BODY held ITEM. Return true when the item did something with the click, so it does not go on to edit the world; the default hand holds things but does nothing with them.
(session)(body session type)Take out BODY's item of TYPE -- from the pocket, or newly made -- or put it away when it is already the thing in hand. Returns what is now held.
Gravitational acceleration, cells per second squared, along Y.
(name (&key label (group :grading) documentation
(class ''scalar-knob)
quantity (type 'single-float)
unit-label minimum maximum step)
place)Define NAME as a knob of CLASS over the setf-able PLACE. PLACE may refer to SESSION, so a knob can live on the session -- its sky clock, its player -- as well as in a special. QUANTITY is a quantity plist as DEFINE-QUANTITY-CONSTANT takes, (:quantity ... :unit ...); it and TYPE make the knob's declaration, which…
Substeps per step: the Soft Step loop runs this many times.
(session)(session)(session)(session)(world)
The things with weight: what the block world does with its physics.
PHYSICS.LISP simulates spheres and knows nothing about the game; this is the game's side of that seam. It decides what a body looks like (a kind: a colour, a pattern, a glow, a size, a bounce), draws every body as a true ray-traced sphere -- one instance record per body for the sphere pipeline's camera-facing quads, patterned and lit in the shader (LUVCRAFT/SHADERS.LISP, role :PHYSICS-SPHERE) -- while the shadow pass keeps rasterizing each body as a small turning cube, posts the player and the animals into the step as kinematic boxes so a ball rolls off a turtle and a walking player kicks what is in the way, and gives the world these ways to make bodies:
ball, a hand item (B takes it out): left click throws one, rightclick drops a whole handful; balls bounce, roll, pile up, and sleep;
scatter-party-balls, which bursts a deterministic party of beachballs, smiley balls, and classic balls around a point;
one another and splash out on whatever they land on;
where they land, cool, and go out.
The events the step reports come back here too: a hit on a box owned by an animal startles it (
critter-struck), and the step's own facts -- how many bodies are awake, how long it took -- are read off the world for the metabar's knobs.