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.

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.

Module contents

Types

TypeKindDescription
ConfigtypeDefines everything a layer decides about its contents.
SorttypeSelects how a layer orders its own contents.

Functions

FunctionKindDescription
bandOffunctionReturns the two terms depthIn takes, resolved once for one layer.
configurefunctionSets what one layer does with its contents.
depthInfunctionReturns one entity's depth on a band bandOf already resolved.
depthOffunctionReturns one entity's depth from zero to one, with zero nearest.
entryOffunctionReturns the four numbers that position and light one layer.
extentsfunctionReturns the authored extents every sort normalizes against.
isOverlayfunctionReturns whether a layer always takes the sorted forward lane.
isScreenSpacefunctionReturns whether a layer measures positions in target pixels.
parallaxOffunctionReturns how much of the camera's movement a layer's contents take.
placefunctionReturns where one authored position lands on the render target.
resolutionfunctionReturns the smallest depth difference depthOf produces between two entities one world unit apart, taken over every...
revisionfunctionReturns the configuration revision.
setExtentsfunctionReplaces the authored extents every sort normalizes against.
setVirtualSizefunctionReplaces the authored resolution every virtual-coordinate layer is measured in.
sortOffunctionReturns a layer's sort as the identifier depthIn accepts.
viewCulledfunctionReturns whether the camera's view rectangle decides if a layer draws.
virtualSizefunctionReturns the authored resolution every virtual-coordinate layer is measured in.

Values

ValueKindDescription
MAXvariableThe number of bands that divide the depth range.
MODE_CAMERAvariablePositions contents in world units, through the camera.
MODE_SCREENvariablePositions contents in target pixels, ignoring the camera.
MODE_VIRTUALvariablePositions contents in the authored virtual resolution, stretched to the target.
SORT_ISOMETRICvariableSorts by x plus y plus height for a diamond grid.
SORT_TOPDOWNvariableSorts lower screen positions in front and breaks ties with height.
SORT_ZvariableSorts only by height and ignores world position.

Types#

Configtype#

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.

Sorttype#

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#

bandOffunction#

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

NameTypeDescription
layerinteger

the band to resolve; outside one to MAX this resolves the nearest layer whole, so the sort answered is the clamped layer's

Returns

TypeDescription
number

the band's near edge, then the sort identifier

integer

configurefunction#

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

NameTypeDescription
layerinteger

the band to configure, from one to MAX

configConfig

the complete replacement configuration

Returns

TypeDescription
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

depthInfunction#

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

NameTypeDescription
basenumber

the band's near edge, from bandOf

sortinteger

the sort identifier, from bandOf

znumber

the height in the sort, normalized against the height extent

xnumber

the world x, read only by the isometric sort

ynumber

the world y, read by the topdown and isometric sorts, larger being nearer

Returns

TypeDescription
number

a depth inside the band, held between 0.001 and 0.999

depthOffunction#

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

NameTypeDescription
layerinteger

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

znumber

the height in the sort, normalized against the height extent

xnumber

the world x, read only by the isometric sort

ynumber

the world y, read by the topdown and isometric sorts, larger being nearer

Returns

TypeDescription
number

the depth inside the layer's own band

entryOffunction#

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

NameTypeDescription
layerinteger

the band to read; outside one to MAX this answers the defaults an unconfigured layer carries rather than raising

Returns

TypeDescription
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

extentsfunction#

function extents(): number, number

Returns the authored extents every sort normalizes against.

Returns

TypeDescription
number

the highest height a scene expects to use, then half the expected world extent

number

isOverlayfunction#

function isOverlay(layer: integer): boolean

Returns whether a layer always takes the sorted forward lane.

Arguments

NameTypeDescription
layerinteger

the band to read; outside one to MAX this answers false, as an unconfigured layer does

Returns

TypeDescription
boolean

whether configure selected overlay for the layer

isScreenSpacefunction#

function isScreenSpace(layer: integer): boolean

Returns whether a layer measures positions in target pixels.

Arguments

NameTypeDescription
layerinteger

the band to read; outside one to MAX this answers false, as an unconfigured layer does

Returns

TypeDescription
boolean

whether configure selected screenSpace for the layer

parallaxOffunction#

function parallaxOf(layer: integer): number

Returns how much of the camera's movement a layer's contents take.

Arguments

NameTypeDescription
layerinteger

the band to read; outside one to MAX this answers one, as an unconfigured layer does

Returns

TypeDescription
number

the parallax factor, one moving contents with the world and a half drifting them at half speed

placefunction#

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

NameTypeDescription
layerinteger

the band whose mode decides what the position means; outside one to MAX this places through the camera, as an unconfigured layer does

xnumber

the authored horizontal position, in world units, target pixels, or virtual units according to the layer's mode

ynumber

the authored vertical position, running down in every mode

cameraXnumber

the view center's world x, read only by a camera layer

cameraYnumber

the view center's world y, read only by a camera layer

zoomnumber

the camera's zoom, read only by a camera layer that does not ignore it

rotationnumber

the camera's rotation in radians, read only by a camera layer

widthnumber

the render target width in pixels

heightnumber

the render target height in pixels

Returns

TypeDescription
number

the pixels from the target's left edge, then the pixels from its top edge; neither is clamped to the target

number

resolutionfunction#

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

TypeDescription
number

the depth difference, in the input that moves depth least

revisionfunction#

function revision(): integer

Returns the configuration revision.

Returns

TypeDescription
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

setExtentsfunction#

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

NameTypeDescription
highestZnumber

the highest height a scene expects to use

halfExtentnumber

half the expected world extent, used by the position terms

Returns

TypeDescription
nil

Raises

  • when either extent is not greater than zero

setVirtualSizefunction#

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

NameTypeDescription
widthnumber

the authored width in virtual units

heightnumber

the authored height in virtual units

Returns

TypeDescription
nil

Raises

  • when either dimension is not greater than zero

sortOffunction#

function sortOf(layer: integer): integer

Returns a layer's sort as the identifier depthIn accepts.

Arguments

NameTypeDescription
layerinteger

the band to read, from one to MAX

Returns

TypeDescription
integer

the sort identifier, which is an internal number rather than a Sort string

viewCulledfunction#

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

NameTypeDescription
layerinteger

the band to read; outside one to MAX this answers true, as an unconfigured layer does

Returns

TypeDescription
boolean

whether extraction should write this layer's real world bound

virtualSizefunction#

function virtualSize(): number, number

Returns the authored resolution every virtual-coordinate layer is measured in.

Returns

TypeDescription
number

the authored width, then the authored height, both in virtual units

number

Values#

MAXvariable#

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_CAMERAvariable#

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_SCREENvariable#

const MODE_SCREEN: number

Positions contents in target pixels, ignoring the camera.

MODE_VIRTUALvariable#

const MODE_VIRTUAL: number

Positions contents in the authored virtual resolution, stretched to the target.

SORT_ISOMETRICvariable#

const SORT_ISOMETRIC: integer

Sorts by x plus y plus height for a diamond grid.

SORT_TOPDOWNvariable#

const SORT_TOPDOWN: integer

Sorts lower screen positions in front and breaks ties with height.

SORT_Zvariable#

const SORT_Z: integer

Sorts only by height and ignores world position.