Digilines 2D Graphics Processor
===============================

Commands for this part are in the form of a table, consisting of a field called "command" with the command to be executed, and other fields supplying parameters to the command.
Example:
	{command="send",buffer=0,channel="example"}

Up to 32 commands may be sent at once by placing all of the tables into one.
Example:
	{
		{command="createbuffer",buffer=0,xsize=16,ysize=16,fill="aaaaaa"},
		{command="send",buffer=0,channel="example"}
	}
	
Invalid commands or commands with missing/invalid parameters will be ignored.

Command: createbuffer
---------------------

Creates a new buffer. Up to 8 buffers may exist at one time, and each can be up to 64x64 pixels in size.

Parameters:
buffer [integer 0-7]: The slot number to create the new buffer in. If the slot is already occupied, the existing contents will be erased.
xsize [integer 1-64]: The width of the new buffer in pixels.
ysize [integer 1-64]: The height of the new buffer in pixels.
fill [hex color, default "000000"]: A color to fill the new buffer with.

Command: send
-------------

Sends the contents of a buffer to a digiscreen, rgblightstone panel, or other digilines device.

Parameters:
buffer [integer 0-7]: The buffer to send the contents of.
channel [string]: The digilines channel to send the message on.

Command: sendregion
-------------------

Sends part of the contents of a buffer to a digiscreen, rgblightstone panel, or other digilines device.

Parameters:
buffer [integer 0-7]: The buffer to send part of the contents of.
channel [string]: The digilines channel to send the message on.
x1 [integer 1-64]: The X position of the left side of the region to send.
x2 [integer 1-64]: The X position of the right side of the region to send.
y1 [integer 1-64]: The Y position of the top side of the region to send.
y2 [integer 1-64]: The Y position of the bottom side of the region to send.

Command: drawrect
-----------------

Draws a rectangle with optional border on a buffer.

Parameters:
buffer [integer 0-7]: The buffer to draw the rectangle on.
x1 [integer 1-64]: The X position of the left side of the rectangle.
x2 [integer 1-64]: The X position of the right side of the rectangle.
y1 [integer 1-64]: The Y position of the top side of the rectangle.
y2 [integer 1-64]: The Y position of the bottom side of the rectangle.
fill [hex color, default "000000"]: The color of the rectangle.
edge [hex color, default same as fill]: The color of the outside edge of the rectangle.

Command: drawpoint
------------------

Draws a point on a buffer.
This command is intended for use when writing a single pixel at a time.
For writing large blocks at one time, it is recommended to use the "load" command instead.

Parameters:
buffer [integer 0-7]: The buffer to draw the point on.
x [integer 1-64]: The X position of the point.
y [integer 1-64]: The Y position of the point.
color [hex color, default "000000"]: The color of the point.

Command: copy
-------------

Perform a BitBLT operation (such as copying one buffer to another).

Parameters:
src [integer 0-7]: The buffer to copy from.
dst [integer 0-7]: The buffer to copy to. May be the same or different from "src".
srcx [integer 1-64]: The X position of the left side of the region to copy from.
srcy [integer 1-64]: The Y position of the top side of the region to copy from.
dstx [integer 1-64]: The X position of the left side of the region to copy to.
dsty [integer 1-64]: The Y position of the top side of the region to copy to.
xsize [integer 1-64]: The width of the region to copy.
ysize [integer 1-64]: The height of the region to copy.
mode [string from list below, default "normal"]: The blend mode to use for the copy operation.
transparent [hex color, default "000000"]: The color to treat as transparency when using the "overlay" blend mode. No effect in other modes.

Blend modes:
normal: Copy the source to the destination, overwriting the destination.
nop: Do nothing.
overlay: Same as normal, but skip pixels in the source matching the "transparent" color.
add: For each subpixel (red, green, blue) add the source values to the destination and write the sum to the destination.
sub: For each subpixel (red, green, blue) subtract the source values from the destination and write the difference to the destination.
isub: For each subpixel (red, green, blue) subtract the destination values from the source and write the difference to the destination.
average: For each subpixel (red, green, blue) calculate the average of the source and destination and write the average to the destination.
and: Perform a bitwise AND of the source and destination and write the result to the destination.
or: Perform a bitwise OR of the source and destination and write the result to the destination.
nand: Perform a bitwise NAND of the source and destination and write the result to the destination.
nor: Perform a bitwise NOR of the source and destination and write the result to the destination.
xor: Perform a bitwise XOR of the source and destination and write the result to the destination.
xnor: Perform a bitwise XNOR of the source and destination and write the result to the destination.
not: Perform a bitwise NOT of the source and write the result to the destination.
rgbtohsv: Convert the source from the RGB color system to the HSV color system and write the result to the destination, storing hue as "red", saturation as "green", and value as "blue".
hsvtorgb: Convert the source from the HSV color system to the RGB color system, reading hue from the red channel, saturation from the green channel, and value from the blue channel, and write the result to the destination.

Command: load
-------------

Transfer a bitmap image into a buffer.
The width and height of the image will be automatically determined from the data given.

Parameters:
buffer [integer 0-7]: The buffer to write the image into.
x [integer 1-64]: The X position of the left side of the image.
y [integer 1-64]: The Y position of the top side of the image.
data [2D array of hex color values, default for each is transparency]: The bitmap image to write.

Command: text
-------------

Draw one or more text characters on a buffer.
The font being used is 5*12 pixels in size, with one pixel spacing between characters.

Parameters:
buffer [integer 0-7]: The buffer to draw the text on.
x [integer 1-64]: The X position of the left side of the text.
y [integer 1-64]: The Y position of the right side of the text.
color [hex color, default "ff6600"]: The color of the text.
text: The text string to draw.

Command: drawline
-----------------

Draws a line on a buffer.

Parameters:
buffer [integer 0-7]: The buffer to draw the line on.
x1 [integer 1-64]: The X position of the start of the line.
x2 [integer 1-64]: The X position of the end of the line.
y1 [integer 1-64]: The Y position of the start of the line.
y2 [integer 1-64]: The Y position of the end of the line.
color [hex color, default "000000"]: The nominal color of the line (may not be the color of every pixel, see the "antialias" setting)
antialias [boolean, default false]: Whether to apply a (very) crude smoothing algorithm to the line to reduce jagged edges at the expense of making the line slightly blurry.

Command: sendpacked
-------------------

Converts the image in a buffer into a string representation that can be loaded again later with the "loadpacked" command.
The result uses 4 bytes per pixel and consists entirely of printable characters (A-Z, a-z, 0-9, +, and /).

Parameters:
buffer [integer 0-7]: The buffer to convert.
channel [string]: The digilines channel to send the packed image on.

Command: loadpacked
-------------------

Load a string representation of an image (created by the "sendpacked" command) back into a buffer.

Parameters:
buffer [integer 0-7]: The buffer to load the image into.
x [integer 1-64]: The X position of the left side of the image.
y [integer 1-64]: The Y position of the top of the image.
xsize [integer 1-64]: The width of the image. Must be the same as the original image or the image will be severely distorted.
ysize [integer 1-64]: The height of the image. Should be the same as the original image.
data [string]: The packed image to load.

Command: fakeshader
-------------------

Allows you to run code that executes for every pixel in a buffer. It isn't a "real" shader because it isn't ran on the GPU and it is ran only on a CPU single thread.

Parameters:
buffer [integer 0-7]: The buffer to run the shader on
code [string, lua code]: The code of the shader

The code that you write gets called for each pixel, and has to return the r, g, b values (integers between 0 and 255)

In order to prevent abuse and lag, the shader code has some limitations:
- The shader can only run for 200*64*64 instructions (this is more than the mesecons luacontroller, but you are not allowed to use the laggy string operation instructions, and in practice it's less)
- Declaring strings is not allowed
   - More specifically, you cannot have in your code: " ' [[ [<any amount of equal signs>[
   - **You also cannot have those characters in comments, and you cannot declare multi line comments**
   - If possible, try minimizing the amount of comments, so you don't accidentally run into this restriction
   - This was done because it would be difficult to limit string concatination and declaring long strings if they were allowed.
- The maximum length of your code is 1000 characters

The environment of shaders (the only things avaliable in shader code):
- math: All standard math functions as documented in the lua manual, except math.randomseed
- xsize: The width of the buffer
- ysize: the height of the buffer
- x: The current x coordinate of the pixel that is being processed
- y: The current y coordinate of the pixel that is being processed
- r: The red value of the current pixel being processed
- g: The green value of the current pixel being processed
- b: The blue value of the current pixel being processed
- get_color(x, y): Allows you to get a color from the buffer, returns 3 values: r, g, b

If the shader code is invalid or throws an error, the digilines GPU will send the error message to digilines, under the channel that it has been configured with.


Shader code examples (inside "```"):

Gradient:
```
return (x/xsize)*255, (y/ysize)*255, 0
```

Grid:
```
return 255*math.sin(x/2), 255*math.sin(y/2), 0
```

Noise:
```
return math.random()*255, math.random()*255, math.random()*255
```

Classic showcase of how RGB works:
```
local radius = 16 -- radius, not named "r" because that would shadow the "r" global
local dist = 10 -- distance between circles
local cX, cY = x-(xsize/2), y-(ysize/2) -- center X, center Y
local r2 = radius^2

local red_circle   = r2 - (cX^2+(cY+dist)^2) -- thanks pythagoras
local green_circle = r2 - ((cX+dist)^2+cY^2)
local blue_circle  = r2 - ((cX-dist)^2+cY^2)

-- make them solid
red_circle, green_circle, blue_circle =
 math.min(1, red_circle)*255,
 math.min(1, green_circle)*255,
 math.min(1, blue_circle)*255

return red_circle, green_circle, blue_circle
```

I am pretty sure you could also run the Conway's Game of Life with this, but that is an excercise for the viewer.

Command: convolutionmatrix
-------------------------
See https://en.wikipedia.org/wiki/Kernel_(image_processing)

Allows you to blur/sharpen/edge detection or do other fun stuff on an image using some numbers in a table. Feel free to experiment.

Parameters:
buffer [integer 0-7]: The buffer to perform the operation on
matrix [nested 3x3 or 5x5 table]: The convolution matrix/image kernel

Example:
{
   command = "convolutionmatrix",
   buffer = 0,
   matrix = { -- edge detection
      { 0, 1 , 0},
      { 1, -4, 1},
      { 0, 1 , 0}
   }
}

Command: transform
------------------
Allows you to rotate/shear/scale/move an area of a buffer.

See:
https://en.wikipedia.org/wiki/Affine_transformation#Image_transformation
https://en.wikipedia.org/wiki/Rotation_matrix

Parameters:
buffer [integer 0-7]: The buffer to perform the operation on.
x1 [integer 1-64]: x1, y1, x2, y2 will be the region that the transform will operate on.
y1 [integer 1-64]
x2 [integer 1-64]
y2 [integer 1-64]
matrix [2x2 nested table or 3x3 nested table]: The transformation/affine matrix, feel free to experiment
center_x [number] - The X coordinate for the center of the transformation (for example the center of a rotation), can be any number, doesn't even need to be on the buffer
center_y [number] - The Y coordinate for the center of the transformation (for example the center of a rotation), can be any number, doesn't even need to be on the buffer
interpolation [boolean, default: true]: If true or unspecified, uses bilinear interpolation, if false it uses nearest neighbor

Examples:
{
   command = "transform",
   buffer = 0,
   x1 = 0, y1 = 0, x2 = 64, y2 = 64,
   center_x = 32, center_y = 32,
   matrix = {
      {1,0.5,0},   -- changes to X coordinate ( when it is {1,0,0} nothing changes, in this case it will shear a bit)
      {0,1,0},     -- changes to Y coordinate ( when it is {0,1,0} nothing changes)
      {0,0,1}      -- changes to perspective (if you change this then it isn't an affine transform) (when it is {0,0,1} nothing changes)
   },
   interpolation = false
}


local angle = math.pi/4 -- 45 degrees
{
   command = "transform",
   buffer = 0,
   x1 = 0, y1 = 0, x2 = 64, y2 = 64,
   center_x = 32, center_y = 32,
   matrix = { -- rotates by the angle
      {math.cos(angle), -math.sin(angle)},
      {math.sin(angle), math.cos(angle},
   },
   interpolation = false,
}
