# `tecs.gfx.layers` Depth bands, sorting, coordinate spaces, parallax, and lighting. A layer occupies one of sixteen depth bands. Entities sort inside their own band and never against another band, so a heads-up display on layer 8 covers a world on layer 1. Extraction turns a layer, a height, and a world position into one depth from zero to one, with zero nearest. ```nupp tecs.gfx.layers.configure(1, {sort = "topdown", parallax = 0.4}) tecs.gfx.layers.configure(8, {sort = "z", screenSpace = true, unlit = true, overlay = true}) world:spawn( tecs.ecs.Transform2D(16, 16, 0, 8, 0, 96, 24), tecs.gfx.Tint(1, 1, 1, 1), tecs.gfx.Renderable2D ) ``` The fourth `Transform2D` argument selects the layer. The table is process-wide, in the same way component identity is, because one process drives one renderer and a scene's authored depth order cannot differ between two worlds in it. `setExtents` names the authored ranges each sort normalizes against. A scene reaching past an extent still draws, resting on the edge, and stops sorting against its neighbors there. # Coordinate spaces World coordinates are the default. `screenSpace` measures a position in target pixels and ignores the camera, which is what a heads-up display wants. `virtualCoords` measures it in the one authored resolution `setVirtualSize` names and stretches that resolution to fill the target. `ignoreZoom` follows the camera's position while keeping the drawn size, and `parallax` scales how far the camera carries the contents. `place` resolves all four into one target pixel, and one layer cannot combine `screenSpace` with `virtualCoords`. `unlit` marks contents that bypass scene lighting, and `overlay` marks contents that always take the sorted forward lane. Both reach a renderer through `entryOf` and `isOverlay` rather than changing anything this module computes. ## Types ### `Config` _type_ ```nupp type Config = { sort: Sort, screenSpace: boolean?, ignoreZoom: boolean?, virtualCoords: boolean?, unlit: boolean?, overlay: boolean?, parallax: number? } ``` Defines everything a layer decides about its contents. A field left out takes its default, so this says what a layer is rather than amending what it was. `sort` is the one field a caller must set; `screenSpace`, `ignoreZoom`, `virtualCoords`, `unlit`, and `overlay` default to false, and `parallax` defaults to one. ### `Sort` _type_ ```nupp type Sort = "topdown" | "z" | "isometric" ``` Selects how a layer orders its own contents. These identifiers reach configuration a developer writes and are a compatibility surface. ## Functions ### `bandOf` _function_ ```nupp function bandOf(layer: integer): number, integer ``` Returns the two terms `depthIn` takes, resolved once for one layer. A caller writing many depths on one layer resolves the band once here rather than once a row. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to resolve; outside one to `MAX` this resolves the nearest layer whole, so the sort answered is the clamped layer's | #### Returns | Type | Description | | --- | --- | | `number` | the band's near edge, then the sort identifier | | `integer` | | ### `configure` _function_ ```nupp function configure(layer: integer, config: Config): nil ``` Sets what one layer does with its contents. Replaces the layer's configuration rather than amending it, so every omitted field takes its default instead of keeping its previous value. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to configure, from one to `MAX` | | `config` | `Config` | the complete replacement configuration | #### Returns | Type | Description | | --- | --- | | `nil` | | #### Raises - when the layer is outside the band range, when the sort is unknown, or when one layer asks for screen pixels and virtual coordinates at once ### `depthIn` _function_ ```nupp function depthIn(base: number, sort: integer, z: number, x: number, y: number): number ``` Returns one entity's depth on a band `bandOf` already resolved. #### Arguments | Name | Type | Description | | --- | --- | --- | | `base` | `number` | the band's near edge, from `bandOf` | | `sort` | `integer` | the sort identifier, from `bandOf` | | `z` | `number` | the height in the sort, normalized against the height extent | | `x` | `number` | the world x, read only by the isometric sort | | `y` | `number` | the world y, read by the topdown and isometric sorts, larger being nearer | #### Returns | Type | Description | | --- | --- | | `number` | a depth inside the band, held between 0.001 and 0.999 | ### `depthOf` _function_ ```nupp function depthOf(layer: integer, z: number, x: number, y: number): number ``` Returns one entity's depth from zero to one, with zero nearest. Exact ties carry no tie-breaker of their own. Extraction writes instances in sorted order and the backend draws them in that order, so two entities at one depth resolve the same way every frame: the later one wins. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band, from one to `MAX`; outside that range this takes the nearest layer whole, because a band is the only thing a depth can name | | `z` | `number` | the height in the sort, normalized against the height extent | | `x` | `number` | the world x, read only by the isometric sort | | `y` | `number` | the world y, read by the topdown and isometric sorts, larger being nearer | #### Returns | Type | Description | | --- | --- | | `number` | the depth inside the layer's own band | ### `entryOf` _function_ ```nupp function entryOf(layer: integer): number, number, number, number ``` Returns the four numbers that position and light one layer. A consumer packs these together when `revision` changes rather than reading them per frame, which is why they come back together. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read; outside one to `MAX` this answers the defaults an unconfigured layer carries rather than raising | #### Returns | Type | Description | | --- | --- | | `number` | the positioning mode, then the camera position's multiplier, then one when the layer ignores zoom, then one when the layer is lit | | `number` | | | `number` | | | `number` | | ### `extents` _function_ ```nupp function extents(): number, number ``` Returns the authored extents every sort normalizes against. #### Returns | Type | Description | | --- | --- | | `number` | the highest height a scene expects to use, then half the expected world extent | | `number` | | ### `isOverlay` _function_ ```nupp function isOverlay(layer: integer): boolean ``` Returns whether a layer always takes the sorted forward lane. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read; outside one to `MAX` this answers false, as an unconfigured layer does | #### Returns | Type | Description | | --- | --- | | `boolean` | whether `configure` selected `overlay` for the layer | ### `isScreenSpace` _function_ ```nupp function isScreenSpace(layer: integer): boolean ``` Returns whether a layer measures positions in target pixels. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read; outside one to `MAX` this answers false, as an unconfigured layer does | #### Returns | Type | Description | | --- | --- | | `boolean` | whether `configure` selected `screenSpace` for the layer | ### `parallaxOf` _function_ ```nupp function parallaxOf(layer: integer): number ``` Returns how much of the camera's movement a layer's contents take. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read; outside one to `MAX` this answers one, as an unconfigured layer does | #### Returns | Type | Description | | --- | --- | | `number` | the parallax factor, one moving contents with the world and a half drifting them at half speed | ### `place` _function_ ```nupp function place(layer: integer, x: number, y: number, cameraX: number, cameraY: number, zoom: number, rotation: number, width: number, height: number): number, number ``` Returns where one authored position lands on the render target. The one place the four positioning modes are resolved, so a caller placing geometry and a caller hit-testing it cannot disagree. A camera layer turns and scales the position about the view center, taking parallax before the turn and dropping the zoom afterwards when the layer ignores it. A screen-space layer answers the position unchanged, and a virtual layer scales the authored resolution onto the target. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band whose mode decides what the position means; outside one to `MAX` this places through the camera, as an unconfigured layer does | | `x` | `number` | the authored horizontal position, in world units, target pixels, or virtual units according to the layer's mode | | `y` | `number` | the authored vertical position, running down in every mode | | `cameraX` | `number` | the view center's world x, read only by a camera layer | | `cameraY` | `number` | the view center's world y, read only by a camera layer | | `zoom` | `number` | the camera's zoom, read only by a camera layer that does not ignore it | | `rotation` | `number` | the camera's rotation in radians, read only by a camera layer | | `width` | `number` | the render target width in pixels | | `height` | `number` | the render target height in pixels | #### Returns | Type | Description | | --- | --- | | `number` | the pixels from the target's left edge, then the pixels from its top edge; neither is clamped to the target | | `number` | | ### `resolution` _function_ ```nupp function resolution(): number ``` Returns the smallest depth difference `depthOf` produces between two entities one world unit apart, taken over every sort mode. A depth target must preserve this difference. A format with a larger step keeps the bands, so layer order stays safe, and loses the sort inside them. #### Returns | Type | Description | | --- | --- | | `number` | the depth difference, in the input that moves depth least | ### `revision` _function_ ```nupp function revision(): integer ``` Returns the configuration revision. #### Returns | Type | Description | | --- | --- | | `integer` | a count starting at zero that only rises, so a consumer holding a packed copy can tell whether its copy is still the answer | ### `setExtents` _function_ ```nupp function setExtents(highestZ: number, halfExtent: number): nil ``` Replaces the authored extents every sort normalizes against. Raising an extent lowers the depth difference one world unit is worth, which is what `resolution` reports. #### Arguments | Name | Type | Description | | --- | --- | --- | | `highestZ` | `number` | the highest height a scene expects to use | | `halfExtent` | `number` | half the expected world extent, used by the position terms | #### Returns | Type | Description | | --- | --- | | `nil` | | #### Raises - when either extent is not greater than zero ### `setVirtualSize` _function_ ```nupp function setVirtualSize(width: number, height: number): nil ``` Replaces the authored resolution every virtual-coordinate layer is measured in. One resolution serves every such layer, because a game has one authored layout size. `place` scales it to fill the target, so the layout keeps its internal proportions at any window size and stretches with the window's aspect. It neither letterboxes nor preserves square pixels. #### Arguments | Name | Type | Description | | --- | --- | --- | | `width` | `number` | the authored width in virtual units | | `height` | `number` | the authored height in virtual units | #### Returns | Type | Description | | --- | --- | | `nil` | | #### Raises - when either dimension is not greater than zero ### `sortOf` _function_ ```nupp function sortOf(layer: integer): integer ``` Returns a layer's sort as the identifier `depthIn` accepts. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read, from one to `MAX` | #### Returns | Type | Description | | --- | --- | | `integer` | the sort identifier, which is an internal number rather than a `Sort` string | ### `viewCulled` _function_ ```nupp function viewCulled(layer: integer): boolean ``` Returns whether the camera's view rectangle decides if a layer draws. False on a layer the camera does not place where its world bound says. Screen-space and virtual-coordinate contents have no world position for the view to test, and parallax and zoom independence draw them somewhere the bound does not describe. Extraction gives those contents a bound every view contains, so they draw whatever the camera is looking at, and a layer using none of these modes keeps exact culling. #### Arguments | Name | Type | Description | | --- | --- | --- | | `layer` | `integer` | the band to read; outside one to `MAX` this answers true, as an unconfigured layer does | #### Returns | Type | Description | | --- | --- | | `boolean` | whether extraction should write this layer's real world bound | ### `virtualSize` _function_ ```nupp function virtualSize(): number, number ``` Returns the authored resolution every virtual-coordinate layer is measured in. #### Returns | Type | Description | | --- | --- | | `number` | the authored width, then the authored height, both in virtual units | | `number` | | ## Values ### `MAX` _variable_ ```nupp const MAX: integer ``` The number of bands that divide the depth range. Load-bearing at sixteen. The band formula divides the range by it and a consumer recovers a layer by multiplying a depth by it, so raising it changes every depth a scene has ever recorded. ### `MODE_CAMERA` _variable_ ```nupp const MODE_CAMERA: number ``` Positions contents in world units, through the camera. This value is the first component of what `entryOf` reports, which a renderer packs into a uniform the vertex stage compares against, so it is a compatibility surface rather than an identifier this tree renumbers. ### `MODE_SCREEN` _variable_ ```nupp const MODE_SCREEN: number ``` Positions contents in target pixels, ignoring the camera. ### `MODE_VIRTUAL` _variable_ ```nupp const MODE_VIRTUAL: number ``` Positions contents in the authored virtual resolution, stretched to the target. ### `SORT_ISOMETRIC` _variable_ ```nupp const SORT_ISOMETRIC: integer ``` Sorts by x plus y plus height for a diamond grid. ### `SORT_TOPDOWN` _variable_ ```nupp const SORT_TOPDOWN: integer ``` Sorts lower screen positions in front and breaks ties with height. ### `SORT_Z` _variable_ ```nupp const SORT_Z: integer ``` Sorts only by height and ignores world position.