Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

pixelprotocol

PixelProtocol (pipro) is a protocol for defining what is being sent between the GUI client and the game engine.

It's for implementing games where old-school looking pixel art can be appreciated.

Features and limitations

  • 256 indexed colors.
  • A size of 320x200 pixels is recommended.
  • Should be possible to implement both in 16-bit assembly for DOS and in a browser.
  • 8-channel audio with multiple waveforms, PCM samples and ADSR envelopes.
  • Instruments and pattern-based music with tracker effects.
  • Text rendering with 8 font slots and scaling.
  • Advanced sprite operations including rotation, scaling, and collision detection.
  • Tilemap layers with per-sprite flags.
  • Clipping, camera offsets, fill patterns, draw palettes and blend modes.
  • Textured triangles and bulk pixel transfers.
  • Keyboard, mouse and up to four joysticks.
  • Timing control and frame synchronization.
  • Memory management for palettes and screen buffers.
  • 128 KB of persistent key/value storage per game.

Q&A

  • Q: Wouldn't it be cooler if Vulkan commands was sent instead? Or OpenGL? Or SDL2?

  • A: Protocols for OpenGL over network already exists and I want to keep things really simple.

  • Q: Can't you just use VNC?

  • A: No, I want something specifically for games or demoscene demos that use 320x200 pixels, 256 colors.

Protocol Definition

  • Version: 0.8

Protocol Header

name type description
magic uint32 0x50495052 ("PIPR")
ver uint16 protocol version, 8 for 0.8
width uint16 width
height uint16 height
flags uint16 bit 0: stereo, bit 1: client returns values
commands []byte pairs of bytes: a command, then its argument

All multi-byte values are little-endian. A command is always the command byte followed by the argument byte, in that order on the wire. The commands can be streamed.

A client implements every command in this document and nothing else. Before 1.0 there is no backwards compatibility: a client that reads a version it does not implement stops and reports an error, and so does a client that reads a command this document does not define.

Every one of the 256 command bytes is now spoken for. A command stays one byte and its argument stays one byte, so making room for something new means dropping whatever earns its place least, and raising the version. Before 1.0 that is a straight break.

The palette starts out as the default VGA mode 13h palette. Color index 0 is transparent for sprites.

Client Header

If bit 1 of the header flags is set, the client sends a header of its own before returning any value:

name type description
magic uint32 0x50495052 ("PIPR")
ver uint16 the protocol version the client implements
buffers uint16 how many screen buffers it has, at least 2
flags uint16 what it can do

Client flags: bit 0 stereo, bit 1 audio, bit 2 music, bit 3 joysticks, bit 4 rumble, bit 5 mouse, bit 6 persistent storage. Where a bit is clear the matching commands do nothing and their queries return 0. Panning collapses to mono unless both headers have their stereo bit set.

The value register

For the few commands that need an argument wider than a byte.

cmd uint8 argument
0xf0 clear the value register
0xf1 push a byte into the value register shift left 8 bits, then or in the byte

The register is 32 bits. Commands that read it as a signed value read it as two's complement.

Bulk data

cmd uint8 argument
0xf2 begin blob the argument is the destination

Followed by a uint16 length and that many bytes, padded with 0x00 to an even count.

Destinations: 0 for a string, 1 for the pixels of the chosen sprite, 2 for the palette (RGB triplets from index 0), 3 for the glyphs of the chosen font, 4 for the data of the chosen sample, 5 for the rows of the chosen pattern, 6 for the drawing target, 7 for the chosen rectangle, 8 for the cells of the chosen map layer, 9 for a storage key, 10 for a storage value.

cmd uint8 argument
0x9d set blob encoding 0=raw, 1=run-length

Run-length encoded data is pairs of bytes: a count of 1 to 255 and a value. A count of 0 ends the data early. The uint16 length still counts the encoded bytes. The encoding stays until it is changed.

A blob that holds more than its destination takes is cut, and one that holds less leaves the rest of the destination alone.

The drawing pipeline

Every written pixel goes through the same steps, in this order:

  1. The position is moved by the camera, then dropped if it falls outside the clip rectangle or outside the drawing target.
  2. A color index comes from the pixel color, the sprite, the map cell, the texture, or from interpolation along a line or across a triangle.
  3. The draw palette remaps it.
  4. It is dropped if it is transparent. Sprites, maps, textured triangles, text and copy region honor transparency, the rest ignore it.
  5. The fill pattern keeps it, replaces it with the fill pattern color, or drops it. Clear, the linewise fills, lines, circles, rectangles and untextured triangles honor the pattern, the rest ignore it.
  6. The blend mode mixes it with the pixel already there.
  7. It is written to the drawing target.

The screen palette and the palette RGB values are applied when a buffer is shown, not when it is written.

Coordinates are signed and kept to at least 32 bits, so the camera can push drawing off either edge. Nothing wraps and nothing is clamped: a pixel outside the clip rectangle or the drawing target is dropped.

So that every client draws the same pixels: lines use Bresenham, circles use the midpoint algorithm, triangles and rectangles use a top-left fill rule, outlines are one pixel wide and lie inside the shape, and sprites and textures are sampled with nearest neighbour. Where blending has to land on a palette entry it takes the lowest index with the smallest squared RGB distance.

Commands

Color palette

cmd uint8 argument
0x00 choose palette color prepare for filling the palette
0x01 set red value of chosen palette color set the color
0x02 set green value of chosen palette color set the color
0x03 set blue value of chosen palette color set the color

Drawing pixels

cmd uint8 argument
0x04 choose pixel color prepare for drawing
0x05 set x position
0x06 set y position
0x07 add to x position
0x08 add to y position
0x09 plot draw a pixel
Q&A
  • Q: What is the "add to x position" command for?

  • A: since all arguments are bytes, it's needed to be able to specify X coordinates from 256..320.

  • Q: Isn't that a bit impractical?

  • A: Perhaps, but it makes the protocol very simple and uniform. All commands takes a byte as an argument.

Filling

cmd uint8 argument
0x0a clear fill the clip rectangle with the color

Clear ignores the camera.


cmd uint8 argument
0x0b draw linewise until nonzero or end for filling the pixel buffer
0x0c draw backwards linewise until nonzero or end for filling the pixel buffer

Both start at the pixel position and walk along the row, 0x0b to the right and 0x0c to the left, drawing the pixel color until they meet a pixel that is not index 0 or the edge of the clip rectangle. The pixel position is left where they stopped.

Flipping

cmd uint8 argument
0x0d flip show buffer N, 0 is the default buffer
0x0e sprite flip the same, but only where sprites have been drawn

A flip copies to the display, leaves the buffer alone and does not move the drawing target, so a frame can be drawn on top of the one before it. A sprite flip then forgets where the sprites were, so each one covers only what was drawn since the last flip.

Drawing lines

cmd uint8 argument
0x0f choose color for start of line prepare to draw a line
0x10 choose color for end of line prepare to draw a line

cmd uint8 argument
0x11 set x coordinate for start of line prepare to draw a line
0x12 set y coordinate for start of line prepare to draw a line
0x13 set x coordinate for end of line prepare to draw a line
0x14 set y coordinate for end of line prepare to draw a line

cmd uint8 argument
0x15 add to x coordinate for start of line prepare to draw a line
0x16 add to y coordinate for start of line prepare to draw a line
0x17 add to x coordinate for end of line prepare to draw a line
0x18 add to y coordinate for end of line prepare to draw a line

cmd uint8 argument
0x19 draw a line draw the line

The two colors are interpolated along the line.

Drawing triangles

cmd uint8 argument
0x1a choose color for p0 prepare to draw a filled triangle
0x1b choose color for p1 prepare to draw a filled triangle
0x1c choose color for p2 prepare to draw a filled triangle
cmd uint8 argument
0x1d set x coordinate for p0 prepare to draw a filled triangle
0x1e set y coordinate for p0 prepare to draw a filled triangle
0x1f set x coordinate for p1 prepare to draw a filled triangle
0x20 set y coordinate for p1 prepare to draw a filled triangle
0x21 set x coordinate for p2 prepare to draw a filled triangle
0x22 set y coordinate for p2 prepare to draw a filled triangle
cmd uint8 argument
0x23 add to x coordinate for p0 prepare to draw a filled triangle
0x24 add to y coordinate for p0 prepare to draw a filled triangle
0x25 add to x coordinate for p1 prepare to draw a filled triangle
0x26 add to y coordinate for p1 prepare to draw a filled triangle
0x27 add to x coordinate for p2 prepare to draw a filled triangle
0x28 add to y coordinate for p2 prepare to draw a filled triangle
cmd uint8 argument
0x29 draw a filled or empty triangle 0 for empty, 1 for filled

The three colors are interpolated across the triangle. The winding order does not matter.

Textured triangles

The same three points are used, with texture coordinates that span the chosen sprite.

cmd uint8 argument
0xb8 set u coordinate for p0 0-255 across the texture
0xb9 set v coordinate for p0 0-255 down the texture
0xba set u coordinate for p1
0xbb set v coordinate for p1
0xbc set u coordinate for p2
0xbd set v coordinate for p2
0xbe choose texture sprite the sprite to read texels from
0xbf draw a textured triangle 0=draw all, 1=skip transparent colors

Texturing is affine. Nothing in the protocol carries depth, so a triangle that needs perspective has to be subdivided by the engine.

Randomization

cmd uint8 argument
0x2a choose a random color for the pixel
0x2b choose random colors for the line
0x2c choose random colors for the triangle
cmd uint8 argument
0x2d choose random coordinates for the pixel
0x2e choose random coordinates for the line
0x2f choose random coordinates for the triangle
cmd uint8 argument
0x4b seed the random generator the seed is in the value register

Random colors run from 0 to 255 and random coordinates fall inside the drawing target. The generator is a 32-bit xorshift, so a seeded sequence replays the same everywhere.

Sprites

cmd uint8 argument
0x30 choose sprite ID select a sprite to work with
0x31 set sprite width set sprite width
0x32 set sprite height set sprite height
0x33 clear sprite clear contents
0x34 push pixel adds N pixels of the selected color
0x35 push empty add N transparent pixels
0x36 set x coordinate for drawing the sprite
0x37 set y coordinate for drawing the sprite
0x38 add to x coordinate for drawing the sprite
0x39 add to y coordinate for drawing the sprite
0x3a draw sprite 0=with the sprite transform, 1=without
0x3b set sprite flags a bitmask kept with the sprite
0x3c get sprite flags returns the bitmask (uint16)
0x3d copy sprite copy the chosen sprite into sprite N
0x3e get sprite size 0 for the width, 1 for the height (uint16)

Pixels are pushed left to right, top to bottom. Clearing a sprite or setting its width or height puts the push cursor back at the top left. Pushing past the end drops the extra, and an argument of 0 pushes nothing. A blob to destination 1 fills a sprite in one go.

The draw position is the top left of the sprite before it is rotated or scaled.

Reading pixels

cmd uint8 argument
0x3f get pixel the color index at the pixel position, or in the chosen sprite if the argument is 1 (uint16)

Reading uses the camera, ignores the clip rectangle, sees the drawing target as it was written and not as it is shown, and returns 0 from outside it.

Clipping and camera

cmd uint8 argument
0x4c set clip x
0x4d set clip y
0x4e add to clip x
0x4f add to clip y
0x50 set clip width
0x51 set clip height
0x52 add to clip width
0x53 add to clip height
0x54 reset clip clip to the whole drawing target
0x55 set camera x signed, from the value register
0x56 set camera y signed, from the value register
0x57 reset camera back to 0,0

The camera is subtracted from every drawing coordinate. Clipping is in target pixels and is not moved by the camera. A clip width or height of 0 stops everything from drawing.

Fill patterns

cmd uint8 argument
0x58 set fill pattern 4x4 bits from the value register, the top row first
0x59 set fill pattern color the color used where a bit is set
0x5a set fill pattern mode 0=off, 1=two colors, 2=set bits are transparent

The pattern is aligned to the drawing target, so the camera does not move it.

Draw and screen palettes

These remap color indexes and leave the RGB values from 0x01-0x03 alone. They apply to the color chosen with 0x00.

cmd uint8 argument
0x5b set draw palette entry the chosen color is drawn as this index
0x5c set screen palette entry the chosen color is shown as this index
0x5d set color transparency 0=opaque, 1=transparent
0x5e reset the draw palette also makes only index 0 transparent
0x5f reset the screen palette

Blending

cmd uint8 argument
0x9f set blend mode 0=replace, 1=alpha, 2=add, 3=subtract, 4=average

Blending works on the RGB values behind the two color indexes. Alpha mode uses the sprite alpha, which counts as 255 for everything that is not a sprite.

Convolution Filters

cmd uint8 argument
0x40 set convolution filter 0 blur is 0,1,0,1,1,1,0,1,0 div 5
0x41 set convolution filter 1 flame is 0,1,0,1,1,1,0,0,0 div 4
0x42 set convolution filter 2
0x43 set convolution filter 3 the uint8 is treated as a range from
0x44 set convolution filter 4 0.0 to 1.0
0x45 set convolution filter 5
0x46 set convolution filter 6
0x47 set convolution filter 7
0x48 set convolution filter 8
0x49 set convolution division
0x4a use convolution filter

The filters work on color indexes, not on RGB values. They run over the clip rectangle of the drawing target, read from a copy of it, and clamp at its edges.

Keyboard, Joystick and Mouse

For returning the state of the client:

Commands that return an uint16:

cmd uint8 argument
0x60 is Esc is Escape being pressed?
0x61 is up is W, up or joystick up pressed? args: 0 for any, 1-4 for the player
Player1 has WASD and Joy1, Player2 has arrows and Joy2, Player3 and
Player4 have Joy3 and Joy4
0x62 is left is A, left or joystick left pressed?
0x63 is down is S, down or joystick down pressed?
0x64 is right is D, right or joystick right pressed?
0x65 is A is Return, Comma (,) or joystick A pressed?
0x66 is B is Space, Dot (.) or joystick B pressed?

cmd uint8 argument
0x67 is shift held down uint8 argument: 0 for left, 1 for right, 2 for any, returns 1 for held down
0x68 is alt held down
0x69 is ctrl held down
0x6a is super held down

cmd uint8 argument
0x6b get keybuffer returns: 0 if empty, keycode of first in keybuffer if not empty
0xfa is key held down uint8 argument: keycode, returns: 1 for held down

cmd uint8 argument
0x6c get mouse x coordinate
0x6d get mouse y coordinate
0x6e get mouse buttons returns a bitmask: 1 for left, 2 for right, 4 for middle
0xf9 get mouse wheel signed movement since the last read

cmd uint8 argument
0x6f joy button uint8 argument: button ID, returns: 1 for pressed
0xf3 choose player uint8 argument: 1-4, or 0 for any, used by the commands below
0xf4 get joystick count how many joysticks are connected
0xf5 get joystick buttons returns a bitmask of the first 16 buttons
0xf6 get joystick hat returns a bitmask: 1 up, 2 right, 4 down, 8 left
0xf7 get joystick axis uint8 argument: axis ID, returns the signed position
0xf8 rumble uint8 argument: strength, 0 stops it

cmd uint8 argument
0xef set cursor 0=shown, 1=hidden, 2=hidden and held inside the window

Mouse coordinates are in screen pixels and are not moved by the camera. Signed values come back as two's complement. Under cursor mode 2 there is no pointer to report, so 0x6c and 0x6d return how far the mouse moved since they were last read, which is what mouse-look wants.

A channel must be set up for receiving the uint16 values that are returned by these functions. One uint16 is returned per command, in the order the commands were received. The two commands that return a variable number of values send the count first, so the channel stays self-framing.

Audio

The 8 channels are numbered 0 to 7.

cmd uint8 argument
0x70 set audio channel select channel 0-7 for audio operations
0x71 set note 0-127, 60 is C-4 and 69 is A-4 (440 Hz)
0x72 set finetune signed, -128..127 spans one semitone
0x73 set volume set volume (0-255)
0x74 set waveform 0=pulse, 1=triangle, 2=sawtooth, 3=sine,
4=noise, 5=periodic noise, 6=sample
0x75 set pulse duty 128 is a 50% square wave
0x76 set panning 0=left, 128=center, 255=right
0x77 note on hold if 0, else gate for N ticks
0x78 note off start the release phase
0x79 stop channel stop audio on selected channel
0x7a set envelope attack ticks up to full volume
0x7b set envelope decay ticks down to the sustain level
0x7c set envelope sustain sustain level (0-255)
0x7d set envelope release ticks down to silence
0x7e set channel effect see the effect table
0x7f set channel effect parameter
0xee get free channel the lowest silent channel the sequencer does not own, or 255 (uint16)

A tick lasts 2.5/BPM seconds, so the default 125 BPM gives 50 ticks per second. Clients mix at 44100 Hz or better. Waveform 6 is silent until a sample is bound to the channel.

Channels are picked by hand and are never stolen. A command aimed at a channel the sequencer owns is ignored, so music and sound effects cannot fight over one.

Samples and Instruments

cmd uint8 argument
0xd0 set master volume 0-255
0xd1 choose sample select a sample slot to work with
0xd2 set sample format 0=signed 8-bit, 1=unsigned 8-bit,
2=signed 16-bit
0xd3 set sample rate Hz, from the value register
0xd4 set sample base note the note that plays it untransposed
0xd5 set sample loop mode 0=none, 1=forward, 2=ping-pong
0xd6 set sample loop start in frames, from the value register
0xd7 set sample loop length in frames, from the value register
0xd8 clear sample clear contents
0xd9 choose instrument select an instrument slot to work with
0xda store channel voice as instrument waveform, duty, envelope and sample
0xdb load instrument into channel
0xdc bind chosen sample to instrument
0xdd play sample bind sample ID, set waveform 6 and start it once
0xde set channel frequency Hz, from the value register
0xdf get channel level current output level 0-255 (uint16)

Sample data is sent as a blob to destination 4. A loop length of 0 means no loop. Setting the frequency overrides the note until the next note on.

Music

cmd uint8 argument
0xe0 choose pattern select a pattern slot to work with
0xe1 set pattern rows 1-255
0xe2 clear pattern clear contents
0xe3 set order length number of entries in the song order
0xe4 set order position the entry to write to and play from
0xe5 set order entry the pattern at the order position
0xe6 set tempo BPM (32-255)
0xe7 set speed ticks per row (1-31)
0xe8 set music volume 0-255
0xe9 play music 0=stop, 1=play once, 2=loop
0xea pause music 0=resume, 1=pause
0xeb set music channel mask bit N gives channel N to the sequencer
0xec get music position 0=order, 1=row, 2=tick (uint16)

Pattern rows are sent as a blob to destination 5. A row has one cell per sequencer channel, in ascending channel order, and a cell is 4 bytes: note, instrument, effect, parameter.

In a cell, note 0 means no change, 1-127 is a note and 255 is a note off. Instrument 0 means no change.

The sequencer plays the channels the mask gives it, lowest bit to the lowest channel, and ignores cells beyond them.

Effects
val effect uint8 parameter
0x00 arpeggio two nibbles, semitones to add
0x01 portamento up speed
0x02 portamento down speed
0x03 tone portamento speed towards the note in the cell
0x04 vibrato high nibble speed, low nibble depth
0x05 tremolo high nibble speed, low nibble depth
0x06 volume slide high nibble up, low nibble down
0x07 set panning 0-255
0x08 sample offset start frame, in units of 256
0x09 retrigger every N ticks
0x0a note delay delay by N ticks
0x0b note cut cut after N ticks
0x0c set volume 0-255
0x0d pattern break continue at row N of the next pattern
0x0e pattern jump continue at order position N
0x0f set speed ticks per row, or BPM if above 31

Effects 0x00 to 0x0c also work per channel with 0x7e and 0x7f, for sound effects outside the music.

Text Rendering

cmd uint8 argument
0x80 set font select font 0-7
0x81 set text color color for text foreground
0x82 set text background color color for text background
0x83 set text x position x position for text
0x84 set text y position y position for text
0x85 add to text x position for positions > 255
0x86 add to text y position for positions > 255
0x87 print character print ASCII character
0x88 print string print the last blob sent to destination 0
0x89 set text scale scale factor 1-8
0x8a set text background transparency 0=opaque, 1=transparent
0x8e set letter spacing signed, added to the width of each glyph
0x8f set line height pixels stepped down by a newline, 0 for the font height

Font 0 is built in. Fonts 1-7 start out empty and are sent as a blob to destination 3, as 256 glyphs of 8 bytes each, one byte per row and the high bit on the left.

A glyph is 8 by 8 pixels. Printing one steps the text x position by 8 times the scale, plus the letter spacing. A byte of 10 steps y down by the line height and puts x back where 0x83 or 0x85 last set it. A byte of 13 is skipped. The string stays until another blob is sent to destination 0.

Geometric Primitives

cmd uint8 argument
0x90 set circle center x x coordinate for circle center
0x91 set circle center y y coordinate for circle center
0x92 add to circle center x for coordinates > 255
0x93 add to circle center y for coordinates > 255
0x94 set circle radius radius in pixels
0x95 draw circle 0=outline, 1=filled
0x96 set rectangle x top-left x coordinate
0x97 set rectangle y top-left y coordinate
0x98 add to rectangle x for coordinates > 255
0x99 add to rectangle y for coordinates > 255
0x9a set rectangle width width in pixels
0x9b set rectangle height height in pixels
0x9c draw rectangle 0=outline, 1=filled
0xfb add to rectangle width for widths > 255
0xfc add to rectangle height for heights > 255

These use the pixel color chosen with 0x04. A radius, width or height of 0 draws nothing.

The chosen rectangle is the one that copy region and blob destination 7 work on as well, so it has to be able to cover a whole screen.

Screen buffers

cmd uint8 argument
0x9e set drawing target buffer N, 0 is the default buffer

Every buffer is the size of the screen and keeps its contents until something is drawn to it. Only 0x0d and 0x0e put a buffer on the display. Blobs to destination 6 and 7 go to the drawing target, so a whole frame rendered by the engine can be sent in one go.

Timing and Synchronization

cmd uint8 argument
0xa0 wait frames wait for N display refreshes
0xa1 set frame rate set target FPS (0=unlimited)
0xa2 get frame counter returns current frame number (uint16)
0xa3 reset frame counter reset frame counter to 0
0xa4 sync to vblank wait for vertical blank
0xa5 get milliseconds since the frame counter reset (uint16)
0xed get frames behind frames still to be shown before the client catches up (uint16)

The frame rate starts at 60. Both counters wrap at 65536. With a frame rate of 0 the client refreshes as fast as it can and 0xa0 still waits for that many refreshes.

0xa0 and 0xa4 hold up the client, not the engine, so an engine is free to send commands as fast as the transport takes them. An engine that wants to stay in step polls 0xed and slows down when it climbs.

Tilemap

cmd uint8 argument
0xa6 choose map layer select a layer 0-7 to work with
0xa7 set map width in tiles
0xa8 set map height in tiles
0xa9 set tile size 8 or 16 pixels
0xaa set map cell x in tiles, for reading and writing cells
0xab set map cell y in tiles, for reading and writing cells
0xac set cell the sprite ID at the cell, then step x
0xad get cell the sprite ID at the cell, then step x (uint16)
0xae clear map fill every cell with the argument
0xaf draw map draw only cells whose flags have every bit in the argument, 0 for all
0x8b set map origin x signed pixels, from the value register
0x8c set map origin y signed pixels, from the value register

Stepping x past the map width wraps to the start of the next row, so a whole layer can be filled without touching the cursor. Cells are sent as a blob to destination 8, one byte per cell, row by row.

A cell of 0 is empty and draws nothing. Other cells draw the top left tile-size square of the sprite they name, without the sprite transform. Layers are drawn one command at a time, in the order the engine asks for them.

A layer is drawn with its top left cell at the map origin, moved by the camera and cut down by the clip rectangle. Scrolling is therefore smooth, and layers scroll at different speeds by giving them different origins. The cell cursor has no effect on drawing.

Advanced Sprite Operations

cmd uint8 argument
0xb0 set sprite rotation rotation angle (0-255 = 0-360°)
0xb1 set sprite scale x horizontal scale (128=1.0x)
0xb2 set sprite scale y vertical scale (128=1.0x)
0xb3 set sprite flip 0=none, 1=horizontal, 2=vertical, 3=both
0xb4 check sprite collision 0=bounding box, 1=pixel perfect (uint16)
0xb5 set sprite pivot 0=top left, 1=center, what it turns around
0xb6 set sprite alpha transparency (0=transparent, 255=opaque)
0xb7 choose the other sprite ID the sprite that 0x30 is checked against

Flipping happens first, then scaling, then rotation about the pivot. Collision compares where the two sprites were last drawn, with the transforms they were drawn with, and returns 1 when they touch.

Memory and Data

cmd uint8 argument
0xc0 save palette save current palette to slot N
0xc1 load palette load palette from slot N
0xc2 save screen copy the drawing target into buffer N
0xc3 load screen copy buffer N into the drawing target
0xc4 copy region 0=copy all, 1=skip transparent colors
0x8d set source buffer what copy region reads from, 0 at first

The region is the chosen rectangle in the source buffer, copied to the position set with 0x05-0x08 in the drawing target. A region that overlaps itself is copied as if it went through a spare buffer first.

Persistent Storage

A key/value store of at most 128 KB per storage ID, kept between runs.

cmd uint8 argument
0xc5 set storage ID from the value register, picks the store
0xc6 store value the last value blob under the last key blob
0xc7 load value returns the length of the value for the last key blob, then the bytes as uint16s
0xc8 has key returns 1 if the last key blob is stored
0xc9 delete key remove the last key blob
0xca get key count how many keys are stored (uint16)
0xcb choose key index select key N for 0xcc
0xcc get key returns the length of the chosen key, then the bytes as uint16s
0xcd clear storage erase everything for the storage ID
0xce get storage used bytes used, in units of 256 (uint16)
0xcf flush storage write it out, returns 1 on success

Keys and values are sent as blobs to destination 9 and 10, and stay until another blob replaces them. A key is at most 255 bytes. A load of a missing key returns a length of 0. A store that would pass 128 KB is ignored. Keys keep the order they were first stored in, so 0xcb and 0xcc can walk them.

Program Control

cmd uint8 argument
0xfd reset put all state back to how it started, but keep persistent storage
0xfe toggle fullscreen enable or disable fullscreen mode
0xff exit end the program

About

Experimental protocol for streaming games

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors