Faces' textures with their light worked in, made once and kept until the light changes.
A surface covers its face's lightmap area at one mip level: each pixel is the texture's colour taken through the light table at the light there, blended between the four nearest lightmap samples. A face's light is the sum of its styles' samples, each scaled by the style's value over 256.
cache = Cauldron3D.Bsp.Surfaces.new()
Cauldron3D.Bsp.Surfaces.fetch(cache, bsp, face_index, mip, light)light is a map: :table (rows of 256 colours, brightest first), :rows (how many),
:styles (a map or tuple from style number to scale, 256 being normal; a missing style
is 256) and :unlit (the light of a face with no lightmap, default 255).
For a picture in full colour the map has :rgba instead of :table and :rows: a
palette as Cauldron3D.Texture.colours/1 makes it, for textures without their own.
The surface is then an RGBA texture lit from the world's grey or red-green-blue
lightmaps (Cauldron3D.Bsp's light_channels):
- each lightmap sample's channel is the sum over the face's styles of its sample
times
trunc(colour * scale), a style given in:stylesas a scale or as{scale, {r, g, b}}(a grey lightmap's one sample serving all three channels); a face with no lightmap has:unlitin every channel (default 32768), and with:fixedevery face has that in every channel instead :store, a function of a sample's{r, g, b}, gives the value kept for it (default the sums themselves)- the kept values are blended between the four nearest samples at each texel's
centre, and
:shade, a function of the blended{r, g, b}, gives the three numbers the texture's channels are multiplied by (default each over 32768)
A face whose texture is of kind :masked is {0, 0, 0, 0} where its texture is
colour 255. :scroll moves the texture (not its light) that many of its own pixels
along s.
The cache is an ETS table owned by the process that made it, readable and writable by any; one surface is kept per face and mip.
Summary
Functions
A face's surface at mip from the texture at that mip and the face's lightmap
samples (every style's, in order; nil for an unlit face), its styles at scales.
The cached surface as {:ok, {index, mip}, surface}, or {:missing, job}: everything
make/2 needs to make it, without the world, so it can be handed to another process;
job.key is {index, mip}.
Forget every surface, as when a new world is loaded.
The surface of face index at mip, made now if it is missing or its light has changed.
Make the surface a cached/5 job describes, and keep it in the cache.
An empty cache.
Types
@type cache() :: :ets.tid()
Functions
@spec build( Cauldron3D.Bsp.Face.t(), Cauldron3D.Texture.t(), binary() | nil, 0..3, [number()], map() ) :: Cauldron3D.Texture.t()
A face's surface at mip from the texture at that mip and the face's lightmap
samples (every style's, in order; nil for an unlit face), its styles at scales.
@spec cached(cache(), Cauldron3D.Bsp.t(), non_neg_integer(), 0..3, map()) :: {:ok, {non_neg_integer(), 0..3}, Cauldron3D.Texture.t()} | {:missing, map()}
The cached surface as {:ok, {index, mip}, surface}, or {:missing, job}: everything
make/2 needs to make it, without the world, so it can be handed to another process;
job.key is {index, mip}.
@spec clear(cache()) :: :ok
Forget every surface, as when a new world is loaded.
@spec fetch(cache(), Cauldron3D.Bsp.t(), non_neg_integer(), 0..3, map()) :: Cauldron3D.Texture.t()
The surface of face index at mip, made now if it is missing or its light has changed.
@spec make(cache(), map()) :: Cauldron3D.Texture.t()
Make the surface a cached/5 job describes, and keep it in the cache.
@spec new() :: cache()
An empty cache.