# Pixel buffers

NOTE: This is a rewrite of [gr/pix] that heavily changes its semantics. It's
still a WIP.

The unit at [gr/buf.fs] defines the "pixel buffer" (pixbuf) struct which is used
to shove pixels around. It represents of rectangular grid of pixels of a
particular color encoding [gr/color]. Supported depths are 1, 2, 4, 8, 16, 24
and 32 bits.

This unit only takes care of managing the structure, the memory of the buffer,
line addressing, coordinate selection and bounds checking. Actual pixel
operations are handled by other units such as [gr/blt] or [gr/pat]. In other
words, you can't draw a pixel with the API of this unit.

The buffer memory is organized as a sequence of lines which each line being a
sequence of pixels.

The origin of the buffer, that is, its first address in memory, is the bottom
left of the grid. This is unlike many other systems where the origin is top
left, but it allows us to fit better with [oberon].

Because sub-8bit depths are supported, it means there can be more than a single
pixel packed in a single byte. For this reason, the API of this unit might look
peculiar to someone who hasn't considered the possibility of 1, 2, or 4-bit
depths.

## Target coordinates

Each pixbuf has what we call a "target coordinate" in the form of "tgtx" and
"tgty" fields. This unit doesn't do anything special with them, but drawing
units do. Drawing routines will generally operate on that target.

For example, when doing a block transfer in [gr/blt], the transfer will be done
from the source's target to the destination's target.

Some drawing code can modify the target coordinates, for example in an
auto-increment scheme.

Target coordinates are not bound checked. You can set them to anything. An out
of bounds target will result in a null rectangle in "bounds", which will
generally mean a noop draw operation.

## Invalidate

Whenever the buffer is changed, its "invalidate ( w h pixbuf -- )" method is
called once all drawing is finished. It allows for all kinds of little tricks
such as updating [gr/damage] struct or implementing proxy schemes.

If a drawing routine modifies target coordinates, it should do so after it has
called "invalidate".

## Palette resolution

A pixbuf can contain any type of color encoding, which includes palette-based
colors. A pixbuf has a "palette" field to store a pointer to a palette, but it
otherwise does nothing with it. Drawing routines have to manage palette logic
themselves.

## API

### Struct

struct Pixbuf
  fields buffer width height encoding palette linesz bufsz tgtx tgty
  method invalidate ( w h pixbuf -- )
endstruct

buffer    Points to the first byte of the pixbuf
width     Width in pixels of the pixbuf
height    Height in pixels of the pixbuf
encoding  [gr/color] encoding of the pixbuf
palette   If encoding is palette-based, pointer to palette
linesz    Size in bytes of a line
bufsz     Size in bytes of the allocated buffer
tgtx      Target X
tgty      Target Y

invalidate ( width height pixbuf -- )
  Called after a buffer-mutating operation is done. At that point, target
  coordinate is still valid and can be used to determine the scope of the
  operation. Defaults to a noop.

### Words

newpixbuf ( encoding width height -- pixbuf )
  Allocate a new pixbuf with the specified field values. The "buffer" field
  is initialized to 0 and must be either allocated to assigned to something
  before the pixbuf can be used.

allotbuf ( pixbuf -- )
  Allocate a new buffer of the proper size (considering size and encoding) and
  set "buffer" to it.

target! ( x y pixbuf -- )
  Set "tgtx" and "tgty".

yaddr ( y pixbuf -- a )
  Yields the address of the beginning of the line "y".
  "a" is always aligned to 32-bit.
  Aborts if "y" is out of bounds.

xyaddr ( x y pixbuf -- rem a )
  Yields the 32-bit address containing the pixel at x/y as "a", with "rem" being
  the "remaining" x positions in that address. For example, if we have a 8-bit
  depth, a "x" of 7 would yield rem=3.
  Aborts if "x" or "y" is out of bounds.

bounds ( width height pixbuf -- width height )
  Considering tgtx and tgty, possibly reduce "width" and "height" so that such
  a rectangle at target coordinate fits the pixbuf. If nothing fits, yields
  width=0 height=0.
