graffiti 
A graffiti piece being painted: one view of up to GRAFFITI_MAX_LAYERS layers, in colours that may be translucent.
The layers are alike. Each has its own name, glow and id ("l1", "l2", ...), the bottom one included, so none of the hair's rules for its base layer apply. Layer changes are custom sprite history steps, so undo covers them. The piece keeps no palette: it takes its colours from its paint when it saves, at most GRAFFITI_MAX_COLORS of them. Every change counts the pixels of each colour, so checking a stroke's colour never reads the canvas.
Vars | |
| color_counts | Pixel value -> how many pixels of all the layers hold it, for each value the paint uses; transparent pixels aren't counted. In the order the layers first use them when counted afresh, then as new values come. |
|---|---|
| draw_mask_bits | The draw mask as a compact stroke mask's slots, a bit for each pixel that takes paint, as a poster's canvas has it, or null. A stroke is cut down to it as its points are read (stroke_mask_slots()), so none needs checking. |
| layer_record_cache | Layer id -> its layer_records() record, kept until the layer's pixels or glow change, so a surface session's composite reads only the layers painted since the last one. Studio sessions never composite, so never fill it. |
| next_layer_id | The number the next layer's id takes. Ids are never reused in a draft, so the window's choice of layer survives undo. |
Procs | |
| New | Opens a piece with a layer for each of its own, or a blank one-tile piece. |
| add_color | Checks a colour the player wants to paint with. The piece keeps no palette, so this only says whether the colour can be painted now. |
| add_layer | Adds a blank layer on top, as an undoable step. |
| all_points_allowed | A stroke read from a compact mask cut down to the draw mask lands only where paint may go. |
| apply_step | Also applies the layer swap move_layer() records. A swap undoes itself, so both directions swap. |
| count_colors | Counts every layer's pixels of each colour afresh, in the order the layers first use the colours: layer 1 row by row from the top, then each layer above it. |
| count_points | Counts the pixels a stroke, fill, erasure or placement changed: each point keeps the value it replaced. The other steps change whole layers, which count_colors() counts. |
| has_paint_right_half | Returns whether any layer has paint in the right tile's columns, which narrowing the canvas would lose. |
| layer_count | Returns how many layers the piece has. |
| layer_edited | Returns which views of a layer have paint. Every layer keeps its own map, the bottom one included, so the map moves with its layer. edited_directions only serves the base constructor's blank layer, which New() replaces. |
| layer_entries | Returns the layers as the editor's window lists them. |
| layer_entry | Builds a blank layer under the next id, not yet in the piece. |
| layer_glow | Returns whether a layer's paint glows. |
| layer_records | Returns the layers decoded for graffiti_flatten_records(), read straight from their frames. They flatten to the art graffiti_flatten() makes of the piece serialize_piece() returns, without encoding the layers and decoding them again. Each layer's record is kept until it changes (layer_record_cache). |
| layer_view | Returns a layer's one view. |
| layers_changed | Also counts the colours afresh: a layer came or went with its paint. |
| move_layer | Swaps a layer with the one above or below it, as an undoable step. |
| pixels_changed | Also counts the colours afresh when any view may have changed, as opening a piece, a width change or a layer swap leave them. A change to one view is a step, which transact() or reverse_transact() counts. |
| prepare_selection_placement | Also writes the colours a placement lands as their canonical pixels, and refuses a placement that would take the paint past GRAFFITI_MAX_COLORS colours, and, in a surface session, one that adds paint. A stroke brings one colour, but a placement can bring several, so each one it lands counts, whatever it paints over. |
| remove_layer | Removes a layer, paint and all, as an undoable step. |
| rename_layer | Renames a layer as an undoable step, cleaning the name as a saved piece's layer names are. |
| reverse_transact | Also counts what reversing a step changed. |
| sanitize_transaction | Also writes a stroke's colour as the nine-character pixel it paints, in graffiti_color()'s form, so every pixel value stays canonical. |
| serialize_piece | Returns the piece as the library saves it: every layer, painted or not, each grid indexing a palette of the colours the paint uses, in the order the layers first use them: layer 1 row by row from the top, then each layer above it. A two-tile canvas with nothing painted on its right tile saves one tile wide, though the canvas keeps its width. |
| set_layer_glow | Turns a layer's glow on or off as an undoable step. |
| set_width | Makes the canvas one or two tiles wide where it stands: columns come and go on the right, so paint keeps its place and every layer keeps its id. Paint in columns that go is lost, which has_paint_right_half() lets the caller ask about first. History can't span two widths, so it starts over. |
| stroke_layer_matches | Whether a stroke names the layer it paints by its id as well as its place. The bottom layer is named like any other, so a stroke meant for a layer that undo just moved can't land on another. |
| stroke_mask_slots | Returns draw_mask_bits, which a stroke's compact mask is cut down to as it is read: a check of each point costs about as much as the rest of the stroke (measured). A canvas with a draw mask holds no paint outside it, so an eraser loses nothing by it. |
| transact | Fills by setting each pixel to the fill colour, as the pencil paints: translucent paint blends only when the layers merge. Anything else is applied as a custom sprite workspace applies it. Either way, what changed is counted. |
| used_colors | Returns the colours the paint uses, read from color_counts. Unlike a drawing's, translucent colours keep their alpha, as graffiti_color() writes them. |
| validate_palette_color | Takes any brush colour that shows, until the paint uses GRAFFITI_MAX_COLORS colours: then only those. |
Var Details
color_counts 
Pixel value -> how many pixels of all the layers hold it, for each value the paint uses; transparent pixels aren't counted. In the order the layers first use them when counted afresh, then as new values come.
draw_mask_bits 
The draw mask as a compact stroke mask's slots, a bit for each pixel that takes paint, as a poster's canvas has it, or null. A stroke is cut down to it as its points are read (stroke_mask_slots()), so none needs checking.
layer_record_cache 
Layer id -> its layer_records() record, kept until the layer's pixels or glow change, so a surface session's composite reads only the layers painted since the last one. Studio sessions never composite, so never fill it.
next_layer_id 
The number the next layer's id takes. Ids are never reused in a draft, so the window's choice of layer survives undo.
Proc Details
New
Opens a piece with a layer for each of its own, or a blank one-tile piece.
Arguments:
- piece: A canonical piece, as graffiti_validate_piece() returns it, or null. A piece without layers opens with one blank layer.
add_color
Checks a colour the player wants to paint with. The piece keeps no palette, so this only says whether the colour can be painted now.
Arguments:
- color:
#rrggbbor#rrggbbaatext, in either case.
Returns:
- text: The colour, as graffiti_color() writes it.
- null: It isn't a colour, it paints nothing, or it is new and the paint already uses GRAFFITI_MAX_COLORS colours.
add_layer
Adds a blank layer on top, as an undoable step.
Returns:
- number: The new layer's index.
- 0: The piece already has GRAFFITI_MAX_LAYERS layers.
all_points_allowed
A stroke read from a compact mask cut down to the draw mask lands only where paint may go.
apply_step
Also applies the layer swap move_layer() records. A swap undoes itself, so both directions swap.
Arguments:
- transaction: The step.
- forward: Whether it is applied or reversed.
Returns:
- TRUE/FALSE: Whether the step was one this workspace records itself.
count_colors
Counts every layer's pixels of each colour afresh, in the order the layers first use the colours: layer 1 row by row from the top, then each layer above it.
count_points
Counts the pixels a stroke, fill, erasure or placement changed: each point keeps the value it replaced. The other steps change whole layers, which count_colors() counts.
Arguments:
- transaction: The step, as the history keeps it.
- forward: Whether it was applied rather than reversed.
has_paint_right_half
Returns whether any layer has paint in the right tile's columns, which narrowing the canvas would lose.
Returns:
- TRUE/FALSE
layer_count
Returns how many layers the piece has.
Returns:
- number: 1 to GRAFFITI_MAX_LAYERS.
layer_edited
Returns which views of a layer have paint. Every layer keeps its own map, the bottom one included, so the map moves with its layer. edited_directions only serves the base constructor's blank layer, which New() replaces.
Arguments:
- layer: The layer.
Returns:
- list: Direction -> whether that view has paint.
layer_entries
Returns the layers as the editor's window lists them.
Returns:
- list: list("id", "name", "glow") for each layer, bottom first.
layer_entry
Builds a blank layer under the next id, not yet in the piece.
Arguments:
- name: The layer's name, already clean.
- glow: Whether its paint glows.
Returns:
- list: The layer entry.
layer_glow
Returns whether a layer's paint glows.
Arguments:
- index: The layer.
Returns:
- TRUE/FALSE
layer_records
Returns the layers decoded for graffiti_flatten_records(), read straight from their frames. They flatten to the art graffiti_flatten() makes of the piece serialize_piece() returns, without encoding the layers and decoding them again. Each layer's record is kept until it changes (layer_record_cache).
Returns:
- list: A graffiti_art_decode() record for each layer, bottom first: the colours it paints, the index of each pixel's colour, 0 where transparent, and its glow on every pixel.
layer_view
Returns a layer's one view.
Arguments:
- index: The layer, 1 at the bottom.
Returns:
- list: The frame itself, its pixel rows from the top.
layers_changed
Also counts the colours afresh: a layer came or went with its paint.
move_layer
Swaps a layer with the one above or below it, as an undoable step.
Arguments:
- index: The layer.
- delta: 1 to move it up, -1 to move it down.
Returns:
- TRUE/FALSE: FALSE when
indexnames no layer,deltais neither, or no layer lies that way.
pixels_changed
Also counts the colours afresh when any view may have changed, as opening a piece, a width change or a layer swap leave them. A change to one view is a step, which transact() or reverse_transact() counts.
Arguments:
- direction: The view that changed, or null for all of them.
- layer: The layer that changed.
- points: The step's points, when only they changed.
prepare_selection_placement
Also writes the colours a placement lands as their canonical pixels, and refuses a placement that would take the paint past GRAFFITI_MAX_COLORS colours, and, in a surface session, one that adds paint. A stroke brings one colour, but a placement can bring several, so each one it lands counts, whatever it paints over.
A surface is painted by hand, so its pieces show the staged reveal's work rather than prepared art. A placement there may move, turn, mirror or cut the session's own paint, which never lands more of a colour than it lifts or covers; a paste does, and is refused with a notice.
Arguments:
- transaction: The placement.
Returns:
- TRUE/FALSE: Whether anything changes, within the colour limit and, on a surface, without adding paint.
remove_layer
Removes a layer, paint and all, as an undoable step.
Arguments:
- index: The layer.
Returns:
- TRUE/FALSE: FALSE when
indexnames no layer, or names the only one.
rename_layer
Renames a layer as an undoable step, cleaning the name as a saved piece's layer names are.
Arguments:
- index: The layer.
- name: The player's text.
Returns:
- TRUE/FALSE: FALSE when
indexnames no layer, nothing is left of the name once cleaned, or it wouldn't change.
reverse_transact
Also counts what reversing a step changed.
Arguments:
- transaction: The step.
sanitize_transaction
Also writes a stroke's colour as the nine-character pixel it paints, in graffiti_color()'s form, so every pixel value stays canonical.
Arguments:
- input: The checked transaction.
Returns:
- list: The transaction to apply.
serialize_piece
Returns the piece as the library saves it: every layer, painted or not, each grid indexing a palette of the colours the paint uses, in the order the layers first use them: layer 1 row by row from the top, then each layer above it. A two-tile canvas with nothing painted on its right tile saves one tile wide, though the canvas keeps its width.
Arguments:
- name: The piece's name.
- description: Its description.
Returns:
- list: The canonical piece, as graffiti_validate_piece() would return it.
- null: Nothing is painted, or the paint uses more than GRAFFITI_MAX_COLORS colours.
set_layer_glow
Turns a layer's glow on or off as an undoable step.
Arguments:
- index: The layer.
- glow: Whether its paint glows.
Returns:
- TRUE/FALSE: FALSE when
indexnames no layer or the glow wouldn't change.
set_width
Makes the canvas one or two tiles wide where it stands: columns come and go on the right, so paint keeps its place and every layer keeps its id. Paint in columns that go is lost, which has_paint_right_half() lets the caller ask about first. History can't span two widths, so it starts over.
Arguments:
- canvas_width: GRAFFITI_WIDTH or GRAFFITI_WIDE_WIDTH.
Returns:
- TRUE/FALSE: FALSE for any other width, or for the width the canvas already has.
stroke_layer_matches
Whether a stroke names the layer it paints by its id as well as its place. The bottom layer is named like any other, so a stroke meant for a layer that undo just moved can't land on another.
Arguments:
- transaction: The stroke.
Returns:
- TRUE/FALSE
stroke_mask_slots
Returns draw_mask_bits, which a stroke's compact mask is cut down to as it is read: a check of each point costs about as much as the rest of the stroke (measured). A canvas with a draw mask holds no paint outside it, so an eraser loses nothing by it.
Returns:
- list: The slots, for a one-tile canvas with a draw mask.
- null: The canvas paints everywhere.
transact
Fills by setting each pixel to the fill colour, as the pencil paints: translucent paint blends only when the layers merge. Anything else is applied as a custom sprite workspace applies it. Either way, what changed is counted.
Arguments:
- transaction: The step.
used_colors
Returns the colours the paint uses, read from color_counts. Unlike a drawing's, translucent colours keep their alpha, as graffiti_color() writes them.
Returns:
- list: The colours in color_counts' order, a list the caller may change.
validate_palette_color
Takes any brush colour that shows, until the paint uses GRAFFITI_MAX_COLORS colours: then only those.
Arguments:
- source: This workspace.
- color: A well-formed
#rrggbbor#rrggbbaacolour, in either case.
Returns:
- COLOR_IS_INVALID: The colour paints nothing, or would be one colour too many.