# Reading and writing pixels individually

The unit at [gr/rdwr.fs] is about reading and writing pixels from and to Pixbufs
[gr/buf] as fast as possible, despite the sad fact that doing so is inherently
slow. However, it's also necessary to have this capability as soon as we're
dealing with unaligned pixel operations.

Although ultimately, this unit supplies the words "pixel@" and "pixel!", you'll
seldom use them outside temporary and debugging purposes because those accesses
are as slow as one can get.

## Compiler API for sub-8bit encoding

Reading and writing pixels of sub-8bit encoding involves bit fiddling. Of
course, pixel@ and pixel! do that bit fiddling, but you might also want to
include that bit fiddling in fast HAL routines, which is why this unit provides
a compiler API for that fiddling.

rd1, rd2, rd4, ( -- )
  IN:  A=Input buffer
       R1=Index
  OUT: W=color
       R1=Index preserved

  Read a single color from A at index R1, writing the result in W. As specified
  in [gr/buf], pixel stream is little endian, which means that the A buffer is
  assumed to be a 32-bit number with low bits being leftmost,

wr1, wr2, wr4, ( -- )
  IN:  S=Output buffer
       W=color
       R1=Index
  OUT: S=Modified output buffer
       W=clobbered
       R1=Index preserved

  Write the color in W to Output buffer S at index R1.

?mix1, ?mix2, ?mix4, ( addrop -- )
  IN:  S=Output buffer
       R1=Index or X position
  OUT: S=Mixed output buffer
       W=clobbered
       R1=clobbered

  When writing a partial output buffer, one needs to "mix" it with data in
  memory first, that is, OR in the low (left) part of the output buffer with the
  high (right) part of data in memory, with R1 being the junction point.

  For example, with a 4-bit color encoding and a 32-bit buffer, we have 8 pixels
  in the buffer. If R1 is, let's say 3, it means that we have 3 pixels in the S
  register and 5 pixels in the W register. This means that we apply a $fffff000
  mask to W and OR S in it (we assume that S has a value that fits in $fff,
  because why wouldn't it?).

  After that, you're ready to write S in memory.

  The code generated by this routine checks if R1 indicates that a mix is
  necessary. If it is, reads a 32-bit value from "addrop" into W then mask it
  out so that it can be mixed with S. Then, OR W into S for a mixed buffer.

?trim1, ?trim2, ?trim4, ( addrop -- )
  IN:  R1=X position
  OUT: S=Trimmed output buffer
       R1=Index

  When we begin writing an output in the middle of a pixel group, we need to
  begin with partial data in memory, that is the low (left) part of it, but we
  also need the high part to be zeroed out for new data to be ORed in with
  further wr1/2/4, runs. This is what this routine is about.

  For example, with a 4-bit color encoding and a 32-bit buffer, we have 8 pixels
  in the buffer. If R1 is, let's say 3, it means that we want to keep the
  3 low (leftmost) pixels. We therefore apply a $fff mask to S.

  The code generated by this routine first transforms a X position into an
  index. If the result is 0 (right at the beginning of the buffer), set S to 0.
  Otherwise, read existing buffer from "addrop" supplied at compile time, then
  trim its "right" part.

## API

pixel@ ( x y pixbuf -- color )
  Yields color at x/y. Abort when out of bounds.

pixel! ( color x y pixbuf -- )
  Set color at x/y. Abort when out of bounds.
