Repository navigation
Cabinet projection, display rotation and native input cut-off - #589
Merged
Merged
Conversation
Adds DisplayRotation, which rolls screen cameras about their view axis and turns their lens (field of view, or sensor, lens shift and gate fit for physical cameras) while they render, then restores them. Between frames the cameras stay logical, with the turned image's aspect, so camera scripts are unaffected. It hooks the context rendering callbacks because HDRP derives a camera's view and culling before raising beginCameraRendering. The orbit camera and the ball debug raycast convert mouse input into the turned frame.
WindowProjectionSolver computes the camera that renders the table as if the physical playfield screen were a window into it, seen from a fixed eye: a camera at the eye and an off-centre frustum through the screen's corners. The table is placed by a translation, a rotation about its lateral axis and coupled length/height scaling, so the screen stays a rectangle in table space and the result is an ordinary frustum. The output's quarter turns are baked into the corner order. WindowProjectionCamera applies a solved projection to a camera and restores the camera's own state when disabled. Render pipelines plug in through IWindowProjectionAdapter (metadata, history reset, effective anti-aliasing). DisplayRotation leaves such a camera alone. Tests cover corner mapping for all quarter turns, agreement with the ray-intersection model in float32, the VPX axis mapping, mirroring, VPX's scale-origin offset and invalid setups.
A SingleFading or Rgb mapping only sends levels, and the lamp player starts non-RGB lamps Off, so a plain LightComponent mapped that way never lit. LightApi now switches an off light on when it receives a positive level, like InsertLightApi already does.
The balls a trough creates come from prefabs outside the table, so packaged tables fell back to the default ball. The export now copies each prefab the active troughs reference under the table as a template, points the troughs at the copies while writing and restores everything afterwards, even when the package can't be closed. BallComponent is packaged on these templates only (radius and mass); balls placed in a scene still export as their mesh. The trough's references carry the templates, which it deactivates on import; the ball manager activates balls instantiated from them. CabinetComponent and BackboxComponent are packaged as empty markers, so the player can find the cabinet and backbox.
FillLength scales the table uniformly and moves it along the screen so that, seen from the eye, the playfield's front and rear edges meet the screen's front and rear edges. Both are found by bisection; a setup no scale and shift can satisfy is rejected instead of applied.
The input polling thread relays nothing to the game while the window isn't focused or the game is paused. A gate epoch tags every relayed event, so the simulation releases held actions after a cut-off and drops events from before it while keeping fresh ones, and stick nudge channels return to rest and are refreshed from the native axis state on reopen.
This was referenced Oct 15, 2026
[Medium impact] The PR appears safe to merge; no new actionable issue was found. SummaryAdds display rotation and cabinet projection, packages trough ball templates and cabinet markers, and wakes fading lamps at positive levels.
Reviews (3) · Last reviewed commit: "input: just stop relaying native input w..." · Reviewed by Greptile |
…ack failed ball templates - The simulation releases held actions when it pauses instead of on resume, so a flipper held when pausing doesn't stay on. - The cabinet projection camera restores a custom aspect it found instead of always resetting it. - Exporting gives the troughs their ball prefabs back and removes the template copies when copying a template fails.
Pausing with a flipper up is how a player keeps the ball, so nothing is released when the input is cut off: the gate only drops events while the game is paused or the window isn't focused. On focus loss the native poller releases held keys itself. This replaces the gate epoch, the made-up releases and the nudge axis refresh.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds what the player needs for portrait and cabinet setups: a quarter-turned output for side-mounted screens, and a cabinet projection that renders the playfield as seen through a physical screen lying in a cabinet.
Changes
Game/DisplayRotation.cs): turns the camera output by ±90° for screens mounted on their side. The roll and the lens adjustment are applied in the render pipeline's context callbacks, since HDRP computes view and culling beforebeginCameraRendering.Rendering/CabinetProjection*.cs): a solver that places the table under a physical screen (size, inclination, eye position) and builds an off-centre frustum through the screen's corners. Fit policies are physical size, fit, fit stretched and fill length (the table's top and bottom line up with the screen frame, the default). A render-pipeline adapter interface (ICabinetProjectionAdapter) lets HDRP and URP apply it. Covered byCabinetProjectionSolverTests.CabinetComponent/BackboxComponentmarkers are packaged, so the player can hide cabinet and backbox in the cabinet projection.c5e72c6d8): wake lights on a positive fading level.Related PRs