# `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.