Edd Biddulph

Twitter | CV

Projects

March 2012
BoxTool



BoxTool is a visual fragment shader creation system. Fragment shaders can be created by writing code in a shading language, but without a specialised tool it can be timeconsuming to terminate the display program, edit the shader and recompile in a repeating cycle. As well as giving instant feedback when changes to a shader are made, BoxTool provides a visual interface which can be used by non-programmers. This interface consists of simple boxes and wires which make editing intuitive and mostly eliminates the chance of a 'syntax error'.

The interface is displayed entirely through OpenGL as an overlay over the result from the fragment shader being edited. It can be hidden so that only the shader's output is visible. Multiple shaders can be edited in one session, and an entire session is saved to a single workspace file in BoxTool's XML format. Editing is mostly done by clicking and dragging with the mouse.

In BoxTool there are patches, boxes, wires, pins, and gadgets. A patch is a collection of boxes and each patch is completely disconnected from every other patch. There are multiple patches in a workspace and you can switch between them for editing with the function keys (F1-F6).

Here are a couple of videos showing BoxTool in action:

http://www.youtube.com/watch?v=h0VtUtqJlDA
http://www.youtube.com/watch?v=ymNRMwBzroo




A box can be thought of as representing a function, a small piece of the calculation within a shader. Boxes are displayed as rectangles labelled with interior text. Each box has a number of pins which are shown as smaller rectangles on either the top side or bottom side of the box. Pins have labels too, but their labels are only displayed when the cursor hovers over them in the appropriate mode (modes will be covered later on). If a pin is seated on the top side of a box then it is an input pin, else if it is seated below then it is an output pin. Some boxes have no inputs, and some have no outputs but all usable boxes have at least one pin.

An output pin can be connected to an input pin and vice versa by a wire. Wires are displayed as line segments with small arrows at their centroid indicating the direction of data flow, which is always output-to-input. Clicking LMB on a pin puts you in pin-connecting mode and you can then click LMB again on another pin to connect it. You will then be back in the default editing mode. BoxTool prevents you from creating unmatched connections, or feedback loops (try it and see!). While in default mode, hold X and click LMB on a wire to cut it.

An input pin can also be assigned a constant value. This value is displayed next to the label for input pins without connections. You can edit the value by holding Ctrl and clicking LMB on the input pin.

A gadget is part of a box but it is entirely contained within that box. It forms an interface element that can be used to adjust a value intuitively. It serves the same purpose as a volume-adjustment slider or variable lightswitch. Internally, gadgets map directly to shader uniforms so they do not cause a shader code regeneration when they are adjusted. Pressing Ctrl+U randomizes the values of any gadgets in the selected boxes, which can produce interesting results!



Multiple copies of the same box configuration creates a large
parameter space for varied randomizations.


You cannot create boxes from 'thin air' but you can copy and paste them. This is why the F1 patch is special, because this patch is reserved for the library of basic boxes which you need. One of the powerful features of BoxTool is that in fact you can create a completely new box with your own label and pins or gadgets but this is currently not possible through the interface. To do this, you must manually edit the workspace XML file and be very confident using GLSL. There are no box prototypes, classes, or templates - each box is described completely by one XML element.

There are quite a few features of BoxTool so be sure to check out the command reference (below).



If shader compilation fails, the box that caused a failure is highlighted in red



Holding RMB and dragging allows freehand drawings like the arrows shown here


Interface Commands Reference

LMBUse the left mousebutton to select pins to connect, and to drag boxes. You can also drag out a selection box. Hold Ctrl while selecting to keep the current selection.
MMBDrag the pointer while holding the middle mousebutton to pan the patch editing view.
Ctrl+MMBDrag the pointer while holding a control key and the middle mousebutton to zoom the patch editing view in or out.
RMBHolding the right mousebutton and dragging the pointer creates a freehand drawing which occupies the same space as the boxes, so you can quickly annotate parts of your patch or just doodle.
X+LMBRemove a connection. Hold X and point at a connection wire then click the left mousebutton. The wire you are pointing at is highlighted for you.
Ctrl+LMBEnter pin value editing mode. Enter a value from the keyboard and press enter to set it as a constant for the pin. Only valid for input pins.
Ctrl+PArrange all boxes in the patch into a grid.
Ctrl+URandomise the gadgets of all selected boxes. Randomisation means selecting a random position for the gadget within it's range.
Ctrl+FFocus view on the selected boxes. The view will zoom in or out to best fit the region covered by the boxes.
Ctrl+CCopy the selected boxes into BoxTool's internal clipboard.
Ctrl+VPaste the boxes in BoxTool's internal clipboard to the location being pointed at. You can copy and paste between patches.
Ctrl+ZUndo.
Ctrl+YRedo.
Ctrl+DDelete the selected boxes.
Ctrl+ASelect all boxes in the current patch. If all boxes are already selected, then they will all be deselected.
TabSwitch between patch editing and patch viewing. In patch viewing mode, the BoxTool interface is hidden and no patch-altering actions can be taken. Patch viewing mode lets you fully see the result of your work.
Alt+XDisconnect the selected boxes from any not-selected connected boxes. This allows you to quickly disconnect a group of boxes while keeping the connections you want. You save the time of cutting each connection individually.
IHold I and point at a box to find extra information about it. You will see the ID of the box displayed, which can help if you are editing the BoxTool workspace file in a text editor while running BoxTool.
DEnter freehand drawing removal mode. A circle will be displayed around the pointer. Pressing D more times gives you a bigger circle until you have been through all the available circle sizes and you then leave freehand drawing removal mode. Pressing LMB while in this mode erases any freehand drawings within the circle.
F1-F6The function keys select different patches. You can only view or edit one at a time, but you can copy and paste boxes between patches. Each patch has it's own undo history.
Ctrl+SSave the current state of the workspace. This includes all patches.
Ctrl+RReload the workspace. Be careful with this, as you will lose all of your undo and redo levels in all patches.
Alt+HWrite the current shader to a file. The file's name is generated from the current workspace file, and the index of the current window. It will be found in BoxTool's directory, alongside the executable.




Workspace XML Reference

Note: 'patchspace' refers to the vector space in which box positions, pin positions, and box dimensions are defined.

ElementDescriptionAttributes
BoxToolWorkspace The root node of any workspace file. Can contain one Preamble and multiple PatchWindows. current_window_index is the index of the PatchWindow to show on startup.
Preamble Contains shader source code to be prepended to all shaders. This is where utility functions should go. None.
PatchWindow One of the windows selectable using the function keys. Can contain one Patch. show_interface can be either "1" to show the interface or "0" to hide it.

view_min_x is the x co-ordinate in patchspace of the topleft corner of the viewport.

view_min_y is the y co-ordinate in patchspace of the topleft corner of the viewport.

view_max_x is the x co-ordinate in patchspace of the bottomright corner of the viewport.

view_max_y is the y co-ordinate in patchspace of the bottomright corner of the viewport.

last_action_desc is a description for the last action performed on the patch. It's not required for correct operation, but currently appears in files due to an oversight.
Patch Can contain multiple Boxes and multiple Pencils. allow_edit can be either "1" to allow editing or "0" to disallow it.

pixel_box_num and pixel_box_num0 together identify the pixel box (the final shader output).

auto_arrange_on_load can be either "1" to auto-arrange all boxes into a regular grid or "0" to not do so.
Box Can contain one Body, multiple Pins, and multiple Gadgets. num and num0 together identify the box uniquely within a patch. If they are omitted, then BoxTool will generate them for you.

label is a string of text to name the box with. It does not need to be unique. Multi-line labels are currently not supported.

selected can be either "1" to indicate that the box is selected or "0" to not do so.

x and y define a position in patchspace where the box's topleft corner is located.
Body Contains shader source code for a Box. Pin names must be prepended with an '@'. None.
Pin Can contain multiple Connections. label is a string of text to name the pin with. This string, prepended with an '@', will be replaced by an expression within the enclosing box's body.

input can be either "1" to indicate that this pin is an input or "0" to indicate that it is an output.

value can be specified for use when the pin is not connected. It is usually a number, but can be any valid shader expression.
Gadget Does not contain anything. label is a string of text to name the gadget with. This string, prepended with an '@', will be replaced by an expression within the enclosing box's body.

range_start is the value the gadget represents when it is in the top setting.

range_end is the value the gadget represents when it is in the bottom setting.

position is the current setting of the gadget, it must be 0, 1, or a number between 0 and 1. A position of 0 puts the gadget in the top setting, and a position of 1 puts the gadget in the bottom setting.

size_x and size_y define the width and height of the area in which the gadget's button can be set.

button_size_x and button_size_y define the width and height of the gadget's button.
Connection Does not contain anything. box_num and box_num0 together identify which box the enclosing Pin is connected to.

pin_index identifies which pin in the external box the enclosing Pin is connected to.
Pencil Can contain multiple P elements. None.
P A point in a pencil line. All points in a Pencil are joined up by line segments in the sequence they have in the workspace file. x and y define a position in patchspace.


Download - includes Win32 executable, sourcecode, and CodeBlocks project file. Source code is licensed under the zlib license.
Last updated on 17th June 2012 - please see the included ChangeLog.txt file for details.