Colosseum

A first-person walk through the Colosseum in Rome. Start in the street to the west, pass under the numbered arches, and take the west passage under the seats into the arena. Go down the ramp into the hypogeum, climb the stairs to the upper ambulatory and the top terrace, and find the eight tesserae, the bone tokens that marked a seat. Then take the emperor's box on the south side of the podium. The faster you finish, the higher your score.

Controls:

What to watch for:

How it renders #

Rotunda draws the Pantheon from a 2D BSP, as Doom does. A 2D BSP gives every point on the plan one floor and one ceiling, so it cannot put one room above another. The Colosseum needs rooms above other rooms: the hypogeum under the arena, the upper ambulatory on the lower one, and passages and stairs under the seats.

The level is 1,114 sectors, as in the Build engine behind Duke Nukem 3D. A sector is a convex room with its own floor and ceiling planes, or open sky. At startup each side of a sector is cut wherever a neighbour's side begins or ends. Each piece is then stacked into spans from floor to ceiling: solid wall, an opening into another sector, or open sky. Openings can lead into several sectors stacked above one another. The outer wall, seen from the street, opens into the passages through the lower and upper arches, and onto the top of the parapet. Each arch is six sectors between points on its curve, each with a sloped ceiling plane, so its vault follows the arch through the wall's thickness. The two sides of every wall must agree, and a test checks every opening from both sides.

Each screen column follows its ray from the camera's sector. In a sector, the column draws the floor rows below the far side's foot and the ceiling rows above its head. Between them it draws the spans of the side the ray leaves through. An opening becomes a narrower window of rows into the sector behind it, so each pixel is drawn once and no depth sorting is needed. Floors, slopes and ceilings are cast per pixel onto their planes. The seating cells lie between two rings of the same ellipse, so each one is an exact plane and meets its neighbours without a step.

The same sectors also become 7,027 polygons for a true 3D BSP, built the first time you press B. That renderer walks the tree front to back. It skips subtrees whose bounding boxes cover only pixels already drawn, and scan-converts each polygon that faces you. Both renderers call the same shading for each pixel, and their frames match.

On an Apple M5 in Node.js, before the outer wall was thickened, the sector renderer took 8.8 to 11.0 ms per frame in six fixed views, and the 3D BSP took 10.2 to 12.1 ms. Run back to back, the thicker wall made no measurable difference. Without textures, finding what each pixel shows costs 2.7 to 3.1 ms with sectors and 3.4 to 4.7 ms with the BSP. Sectors win here because every wall is vertical and every floor is one plane per room. The BSP could also draw sloped walls and real overhangs, but it pays for that on every pixel. To reproduce the measurements, run node tools/bench-colosseum-renderers.mjs.

Collision uses the same sectors. You can pass through an opening if it starts no more than a step above your feet and leaves head room. Otherwise its side blocks you, which is how the podium's parapet, the balustrades beside the stairwells, and the piers between the arches stop you. Stairs are runs of small sectors, each half a metre higher than the last.

As a gull you collide the same way, with a smaller body that can rise over a ledge but not climb steps. A test lets a gull wander for 40 seconds and checks that it never leaves the air of its sector. Another test follows every way a walker can step, jump, or fall from room to room, and checks that every room leads back to the street.

Each gull's flight is a series of straight legs and circles. A gull soars above the highest wall top and drops to a perch only from the open side, and a test follows every gull for three minutes to check that none enters a wall. The component simulates fixed 16 ms steps before the events in each update. A late update runs at most eight steps. The title, pause, and end screens request no wakes, and only render writes the 640 by 480 KTX2 frame.