# HID: rendering vs. composite layers

All rendering is driven by the core. The core understands the PCB stackup, layers, layer groups, compositions within the layer groups, extra labels, layer visibility, etc. The HID is a slave device that takes drawing instructions and blindly executes them.

However, the HID has a chance to alter which layer groups are drawn, using the set_layer_group hooks return value.

## Bursts and layer groups

The rendering is done in bursts. A burst may redraw only a small window of the screen. Each bursts draws multiple layer groups, in Z-order, from bottom (furthest from the eye of the user) to up (closest to the eye of the user). Each layer group is drawn on a transparent sketch canvas. In positive mode, objects are drawn with multiple colors on each sketch canvas. In negative mode pixels are erased from the sketch canvas, making the affected pixels transparent again. Drawing on a layer group (either positively or negatively) should overwrite pixels on the same layer group. In other words, there's no translucency between two overlapping objects drawn on the same layer group.

There is a so called output canvas, which shall be cleared to the background color upon render_burst / start. The background color shall be fetched from the config tree (appearance/color/background).

The following steps are taken by the core in a burst:

- 1. call to the render_burst hook with start
- 2. set_layer_group is called for the next layer; depending on the return value, the core will skip to step 7.
- 3. set_drawing_mode is called with reset
- 4. set_drawing_mode is called with positive or negative to set draw or erase
- 5. objects are drawn
- 6. if there are subsequent composite layers, the core will jump back to 3.
- 7. set_drawing_mode is called with flush
- 8. if there are further groups, the core jumps back to step 3.
- 9. call to the render_burst hook with end

When set_drawing_mode / reset is called, the HID needs to create a new sketch canvas, all pixels initialized to transparent. The core may switch between positive and negative draw any time. When set_drawing_mode / flush is called, the current sketch canvas needs to be blitted onto the output (in a HID-specific way) and the sketch canvas can be destroyed. The output canvas shall be flushed to the screen upon render_burst / end.

Optional optimization: the most common case is when only positively drawn layers are used to draw the final output. Drawing on separate sketch canvases and blitting them onto an output buffer is a waste in this setup. To give HIDs a chance to avoid the extra copies, set_drawing_mode calls have an argument called direct. When the direct is set, it is safe to directly draw on the output canvas, without allocating a sketch canvas. The core guarantees the followings:

- all calls of set_drawing_mode within drawing a layer group will have the same direct argument
- if direct is set for a layer group, set_drawing_mode will not be called with negative
- only the first N consecutive layer groups can be direct; once a group is drawn with direct unset, all subsequent groups will be drawn with direct unset

It is possible that the core would draw the whole board in direct mode. It is safe to ignore the direct argument and always use the more expensive, sketch-canvas+blitting method.

## GCs

The API contains Graphic Context, or GC for short. A GC is a pen with properties like color and tip shape. The core will initialize multiple GCs for the drawing and will pass a GC pointer with each drawing command.

Note: this concept is orthogonal to the above canvas based drawing. Regardless of which GC is used, the object being drawn always ends up making modifications to the currently active (sketch) canvas.

A GC can be initialized only after render_burst / start and all GCs will be uninitialized before render_burst / end.

## colors

In negative drawing mode, drawing an object always clear on the current canvas, regardless of the GC color.

In positive drawing mode, objects are drawn with whatever color the current GC has. The special color "drill" is used to draw holes that go thru all layers of the board. It is possible that a drill is drawn over existing objects and new objects are drawn on top of a drilled hole. To get the proper order, the HID shall set the .holes_after to 1.

(Note: there's no "erase" color anymore.)

## transition

When switching over an existing HID from the old use_mask() API to the new composite API:

- set .poly_before to 0
- set .poly_after to 0
- set .enable_fake_composite to 0
- set .holes_after to 1
- use an empty function for .use_mask for now

## XOR drawing

XOR draw is used as a mean to make an object always visible, no matter over what background it is drawns. It is not used as a cheap draw/erase mechanism, so HIDs are free to implement it with a different algorithm - as long as it is guaranteed that objects drawn on the same colored background will stick out.

There are two places XOR draw takes place:

- in core's normal draw procedures (pcb_hid_expose*()), as the very last compsiting canvas (after everything else had been drawn)
- in pcb_draw_attached(), whenever it is called by the HID

In both cases the drawing mode is set to PCB_HID_COMP_POSITIVE_XOR, which does not clear the direct flag. The GC that is used for drawing the actual objects also has its xor mode set.