tecs.gfx.images

Image identity, residency, and the commands that carry pixels to the backend.

A game names an image, hands over its pixels, and receives a small integer that a Sprite stores. The backend owns the texture, the view, the sampler, and the bind group; nothing native reaches game code.

const id = tecs.gfx.images.upload({
    name = "tiles/grass",
    width = 2,
    height = 2,
    pixels = grassRgba8,
    filter = "nearest",
})

world:spawn(
    tecs.ecs.Transform2D(64, 64, 0, 1, 0, 32, 32),
    tecs.gfx.Tint(1, 1, 1, 1),
    tecs.gfx.Sprite(id),
    tecs.gfx.Renderable2D
)

An id is permanent and process-wide, in the same way component identity is, so a snapshot stores the name and resolves the id again on load. Uploading a name twice replaces the image behind that same id, and every sprite already pointing at it draws the new pixels on the next frame.

Residency is observed rather than waited on. upload queues a command and answers immediately with "pending"; the host drains the command, reports the outcome, and stateOf then answers "resident" or "failed". Extraction draws a sprite whose image is not resident against the backend's opaque white fallback, so a missing asset is a visibly untextured quad rather than a dropped entity or a raised error.

Pixels are eight-bit RGBA with unassociated alpha, four bytes per texel, in rows running top to bottom. That is the only accepted layout, and the command names it so a later format costs a value rather than a command shape.

Module contents

Types

TypeKindDescription
AddresstypeSelects what sampling outside the zero-to-one range returns.
Commandtype
FiltertypeSelects minification and magnification filtering.
FormattypeThe pixel layout an upload carries.
MaterialMapstypeOptional companion images; omitted channels use neutral material values.
MaterialMapsCommandrecordOne queued residency request.
ReleaseImageCommandrecordAsks the backend to drop one image and everything bound to it.
StatetypeReports where one named image stands with the backend.
UploadImageCommandrecordAsks the backend to make one image resident under an id.
UploadOptionstypeThe options upload accepts.

Functions

FunctionKindDescription
completefunctionRecords the backend's outcome for one drained command.
drainfunctionRemoves the queued residency commands for the host to apply.
failureOffunctionReturns why the backend rejected one image.
idfunctionReturns the permanent id one image name resolves to.
loadfunctionDecodes a PNG or JPEG file and queues its RGBA pixels for upload.
nameOffunctionReturns the name one image id was interned under.
releasefunctionQueues one image for release.
residencyRevisionfunctionReturns the revision of image residency and sampling metadata.
samplerIndexfunctionReturns the sampler index one filter and address mode select.
samplerOffunctionReturns the sampler index extraction writes for one image.
setMaterialMapsfunctionAssociates normal, emission and packed occlusion/roughness/metallic images.
sizeOffunctionReturns the texel dimensions the last accepted upload declared.
stateOffunctionReturns where one image stands with the backend.
uploadfunctionQueues one image for residency and returns its permanent id.

Values

ValueKindDescription
SAMPLER_COUNTvariableThe number of distinct samplers a backend must create.

Types#

Addresstype#

type Address = "clamp" | "repeat" | "mirror"

Selects what sampling outside the zero-to-one range returns.

These identifiers reach configuration a developer writes and are a compatibility surface.

Commandtype#

Filtertype#

type Filter = "nearest" | "linear"

Selects minification and magnification filtering.

These identifiers reach configuration a developer writes and are a compatibility surface.

Formattype#

type Format = "rgba8"

The pixel layout an upload carries.

This value crosses to the backend inside a command and is a compatibility surface.

MaterialMapstype#

type MaterialMaps = {
    normalMap: integer?,
    emissionMap: integer?,
    ormMap: integer?
}

Optional companion images; omitted channels use neutral material values.

MaterialMapsCommandrecord#

record MaterialMapsCommand
    kind: string
    serial: integer
    image: integer
    normalMap: integer
    emissionMap: integer
    ormMap: integer
end

One queued residency request.

Fields

kind#
kind: string
serial#
serial: integer
image#
image: integer
normalMap#
normalMap: integer
emissionMap#
emissionMap: integer
ormMap#
ormMap: integer

ReleaseImageCommandrecord#

record ReleaseImageCommand
    kind: string
    serial: integer
    image: integer
end

Asks the backend to drop one image and everything bound to it.

Fields

kind#
kind: string

Read-only. Names the command kind, which is a compatibility surface.

serial#
serial: integer

Read-only. Identifies the command for its completion report.

image#
image: integer

Read-only. Selects the process-wide image id to drop.

Statetype#

type State = "unknown" | "pending" | "resident" | "failed" | "released"

Reports where one named image stands with the backend.

UploadImageCommandrecord#

record UploadImageCommand
    kind: string
    serial: integer
    image: integer
    width: integer
    height: integer
    format: Format
    sampler: integer
    pixels: string
end

Asks the backend to make one image resident under an id.

Fields

kind#
kind: string

Read-only. Names the command kind, which is a compatibility surface.

serial#
serial: integer

Read-only. Identifies the command for its completion report.

image#
image: integer

Read-only. Selects the process-wide image id the texture lands under.

width#
width: integer

Read-only. Reports the width in texels.

height#
height: integer

Read-only. Reports the height in texels.

format#
format: Format

Read-only. Names the pixel layout.

sampler#
sampler: integer

Read-only. Selects one of the backend's SAMPLER_COUNT samplers.

pixels#
pixels: string

Read-only. Carries the texel bytes, which the host copies and forgets.

UploadOptionstype#

type UploadOptions = {
    name: string,
    width: integer,
    height: integer,
    pixels: string,
    filter: Filter?,
    address: Address?
}

The options upload accepts.

Functions#

completefunction#

function complete(image: integer, serial: integer, ok: boolean, reason: string?): nil

Records the backend's outcome for one drained command.

A completion that no longer matches the image's newest serial is discarded, so a replacement queued before the previous upload completed keeps its own state.

Arguments

NameTypeDescription
imageinteger

the process-wide image id the command named

serialinteger

the command serial the host applied

okboolean

whether the backend accepted the command

reasonstring?

the non-empty host failure, required when ok is false

Returns

TypeDescription
nil

Raises

  • when a rejection carries no reason

drainfunction#

function drain(): {Command}

Removes the queued residency commands for the host to apply.

Returns

TypeDescription
{Command}

the ordered command batch, which the caller owns

failureOffunction#

function failureOf(image: integer): string?

Returns why the backend rejected one image.

Arguments

NameTypeDescription
imageinteger

the process-wide image id

Returns

TypeDescription
string?

the host failure reason, or nil unless the state is "failed"

idfunction#

function id(name: string): integer

Returns the permanent id one image name resolves to.

Interning a name does not make it resident. A sprite may be built against an id whose pixels arrive later, or never.

Arguments

NameTypeDescription
namestring

the stable image name, which a snapshot stores

Returns

TypeDescription
integer

the process-wide image id, which is always greater than zero

Raises

  • when the name is empty

loadfunction#

function load(path: string, name: string?): integer

Decodes a PNG or JPEG file and queues its RGBA pixels for upload.

Arguments

NameTypeDescription
pathstring

the image file path

namestring?

the stable image name; omitted uses the file path

Returns

TypeDescription
integer

the image id, whose dimensions are immediately available

Raises

  • when the file cannot be decoded

nameOffunction#

function nameOf(image: integer): string?

Returns the name one image id was interned under.

Arguments

NameTypeDescription
imageinteger

the process-wide image id

Returns

TypeDescription
string?

the name, or nil when no image carries that id

releasefunction#

function release(name: string): boolean, string?

Queues one image for release.

The id survives the release, so a later upload under the same name makes the same id resident again. Sprites pointing at a released image draw the backend's fallback until then.

Arguments

NameTypeDescription
namestring

the stable image name

Returns

TypeDescription
boolean

whether a release was queued, which is false for a name nothing uploaded

string?

why nothing was queued, when unsuccessful

residencyRevisionfunction#

function residencyRevision(): integer

Returns the revision of image residency and sampling metadata.

Returns

TypeDescription
integer

A monotonic count that changes when residency or sampling changes.

samplerIndexfunction#

function samplerIndex(filter: Filter?, address: Address?): integer

Returns the sampler index one filter and address mode select.

Arguments

NameTypeDescription
filterFilter?

the filtering mode, defaulting to "nearest"

addressAddress?

the addressing mode, defaulting to "clamp"

Returns

TypeDescription
integer

the sampler index, from zero to SAMPLER_COUNT minus one

Raises

  • when either mode is not one of its declared values

samplerOffunction#

function samplerOf(image: integer): integer

Returns the sampler index extraction writes for one image.

Arguments

NameTypeDescription
imageinteger

the process-wide image id

Returns

TypeDescription
integer

the sampler index, which is nearest filtering with clamped edges for an unknown id

setMaterialMapsfunction#

function setMaterialMaps(image: integer, maps: MaterialMaps): nil

Associates normal, emission and packed occlusion/roughness/metallic images. All supplied maps must have the albedo image dimensions. Applies to sprites and TileChunks using that image; replacement pixels keep the association.

Arguments

NameTypeDescription
imageinteger
mapsMaterialMaps

Returns

TypeDescription
nil

sizeOffunction#

function sizeOf(image: integer): integer, integer

Returns the texel dimensions the last accepted upload declared.

Arguments

NameTypeDescription
imageinteger

the process-wide image id

Returns

TypeDescription
integer

the width and then the height in texels, both zero before an upload

integer

stateOffunction#

function stateOf(image: integer): State

Returns where one image stands with the backend.

Arguments

NameTypeDescription
imageinteger

the process-wide image id

Returns

TypeDescription
State

the residency state, which is "unknown" for an id nothing uploaded

uploadfunction#

function upload(options: UploadOptions): integer

Queues one image for residency and returns its permanent id.

Uploading a name that is already resident replaces its pixels behind the same id, so every sprite pointing at it draws the new image once the host reports the replacement complete.

Arguments

NameTypeDescription
optionsUploadOptions

the name, texel dimensions, RGBA8 pixels, and sampling modes

Returns

TypeDescription
integer

the process-wide image id

Raises

  • when the name is empty, a dimension is not positive, a sampling mode is unknown, or the pixel length is not four bytes per texel

Values#

SAMPLER_COUNTvariable#

const SAMPLER_COUNT: integer

The number of distinct samplers a backend must create.

Every filter paired with every address mode, so a sampler is selected by index and never created on demand.