
Input
A procedure takes inputs, shown on the procedure's left-hand side in the editor. These are data values and information that are your controls to tell the procedure what it should do, and can be driven by preceding procedural logic.

Output
A procedure produces outputs, shown on the procedure's right-hand. These are data values and information that the procedure produces when asked to by subsequent procedural logic.

A special type of output is used to feed generated geometry and placed objects through to the main procedure outputs and into the rendering engine.
Geometry
Point and triangle data is accumulated as primitive operators are used to build 3D geometry. These can be further manipulated on their journey out of your procedure graph. For example; vertex colours can be set, UV coordinates modified, materials applied, and vertex positions adjusted.

Geometry data is mutable, and is modified in the order the operators are evaluated (generally from left to right) through the graph. For example the Move operator will move vertices from one Frame of reference to another.
Placement
Object placement information is accumulated as placement operators apply the resources mapped from the host engine into 3D space. These can be meshes, components, and objects.

Object data is mutable, and is modified in the order the operators are evaluated (generally from left to right) through the graph. For example the Move operator will move objects from one Frame of reference to another.
Types
The fundamental data types supported by Apparance are described in the following table:
Colour | Type | Notes |
---|---|---|
Integer | Whole number values, e.g. 42 | |
Float | Floating point numeric values, e.g. 3.14 | |
Boolean | Logical values, e.g. true or false. | |
Colour | Floating point RGB value | |
Vector | Three-dimensional vector | |
String | String of characters, e.g. "Hello" | |
List | List of values | |
Content | Results of modelling operations | |
Frame | Oriented 3D bounds, modelling construct |
Basic
Standard computer programming types. Singular values, or generally considered a singular concept. Some operators are available for converting most of these into other compatible types.
Integer
Standard 32 bit signed integer values. Can be used to represent values from -2,147,483,648 to 2,147,483,647. Exactly equivalent to the C++ and C# int
type. They take up 4 bytes of storage. Bitwise operators are available to work with int values as bitfields capable of storing 32 bits of information, such as flags.
Integers are used in Apparance to hold various Identifiers and Enumerations as well. These aren't intended to be seen or manipulated as mathematical values, instead used to represent assets (like meshes, objects, and materials) as well as enumerations (such as Units, Axis, Flags, and Options).
Float
Standard 32 but floating point number representation. Capable of representing numbers in the range ±1.5 x 10−45 to ±3.4 x 1038. Exactly equivalent to the C++ and C# float
type. They take up 4 bytes of storage.
Floats are used where a continuous range of values is needed. Many mathematical operators are available to work with floats.
Bool
Bool, or Boolean, values represent logical true or false states. Exactly equivalent to the C++ and C# bool
type. Even though they are normally 1 byte in size, they take up the minimum supported unit of storage in the Apparance synthesis buffers of a 4 byte int.
String
Strings are sequences of characters, stored as a length and a contiguous line of text. Apparance uses the double-byte character system to allow representation of many extended language characters. Some-what equivalent to the C++ wchar_t
type and the C# string
type. They take up one integer for the length and then len+1
bytes of space, rounded up to the next whole integer boundary.
Composite
Types made up of several values of more basic types combined together and carried around together for convenience. Some operators are available for composing new composite values and breaking them apart into their component values.
Vector
Vectors are usually used to represent a 3-dimensional coordiate in space, a spacial direction, or offset, but can be used to store any three float values. They take up 12 bytes of storage (3 x 4 byte floats).
Colour
Colours are stored as four floating-point values, these are the Red, Green, Blue components, plus an additional value usually used for an Opacity or Alpha value. They take up 16 bytes of storage (4 x 4 byte floats).
Frame
Frame are a custom composite type used throughout Apparance to represent an oriented, sized cuboid in 3D space. Generally this would represent the position, size, and orientation of an object, but could equally be used as a frame of reference for building geometry or to be sub-divided up into smaller spaces.
Frames consist of the following components:
- Origin - A vector stating where in space it's 'lower' corner is located.
- Orientation - A tripled of vectors, each representing the direction of an axis; X, Y, and Z. These are always Unit vectors (length 1.0)
- Size - A vector stating the size of the space the frame covers, extending out from the Origin, in the direction of the three Orientation axes.
A Frame takes up 64 bytes (5 x twelve byte vectors + 4 bytes reserved padding).
Special
Functionally complex types, with special use cases and many operators dedicated to working with them.
List
Lists are variable sized collections of data items. Items are stored in order, and each can be any one of the Apparance data types except for Content. A list stores an integer length, an integer for each item, and any storage associated with the value stored there. Lists can contain sub-lists.
Lists, like most Apparance data types, are immutable, and so each time you manipulate a list, you are creating a new one. This means that heavy list manipulation or processing procedures can take up a fair bit of space, this is usually considerably less than the geometry or images being generate or processed. An important consequence though is that you can feed a list value into multiple bits of logic knowing that you are getting the exact list, captured at the point you connected to in each case.
Lists can be used to store simple arrays of all the same value, such as a polyigonal shape or path (list of vectors), or perhaps a list of strings formed from the lines of a text file read directly from disk.
Lists can also be used to store sets of different types, and treated as structures. By building 'pack' and 'unpack' procedures you can wrap up several related values together in to a convenient single value to be easily passed through a series of procedures before being unpacked where needed. This also makes it far easier to add more values that can go along for the ride without having to thread many connections along the same path through your procedural logic.
Content
Many generation operators produce content intended for the rendering engine host to display in your scene. This is managed and propagated out through your procedure graph using the Content
type.

Operators
Operators are the basic building blocks of a procedural system and embody a single modular piece of functionality. These are the 'blocks' you will be placing in the Apparance Editor and wiring together. They can be found in the Browser panels to the left of the Editor window.
Built-in
Much like the operators in a programming language, or the functions in a utility library, these are what you use to compose more complex pieces of logic and the systems you design to perform the high level goals you have for the procedural objects in your world. These are built into Apparance and can't be changed. They are found in the Operators panel of the Editor.
Procedures
You build procedures from Operators and other Procedures to perform, at first simple tasks, and then gradually higher and higher level parts of your systems. Re-use, modularity, and a logical approach to structuring your growing procedure library will help you manage the complexity of even the most advanced procedural systems. Procedures are created and managed in the Procedures Panel of the Editor. They can be placed alike from both Browser panels by dragging them into your graph.
Synthesis
To turn your procedural logic into the output you see in the world, Apparance evaluates your procedure in a systematic way as follows.
Evaluation
Starting at the outputs of your top-level procedure (the one set on an Entity), it progressively digs down into the operator graph, through the many winding paths, all the way to the inputs of the same top-level procedure. On its journey, everywhere it encounters a procedure it digs within, following the connections around it's internals, and perhaps digging further in and in. If it encounters a fundamental Operator however, it invokes the built-in code that implements that Operators functionality. Any procedure or Operator code that requires an input value will temporarily follow that path, back out and into the graph 'above' and follow where-ever that input is connected.
Data Propagation
Once a value has been established, be-it a top-level input, the result of some mathematical calculation operator, or some composite piece of logic, the evaluation returns back along the path it came to be presented to the waiting operator input, or top-level output. Once an operator has gathered all the inputs it requires to complete it's task it can perform any calculations needed and store the result(s) back at its outputs, ready to be propagated back further up the chain.
Sometimes, an operator decides which inputs are needed based on the values the return to it via some other inputs. This means that whole sections of the graph can be skipped and aren't evaluated. For example, the If
operator checks the control input (bool) to see if it should ask for the 'false' input value or the 'true' input value, and then only asks one of them for a value.
It's worth noting that most values are passed around by reference, meaning that the whole value it's propagated around, saving on storage and data copying costs. New data values are only allocated when an operator needs to change it to a new value, or generate some result based on its inputs. A consequence of this is that Lists of values are very efficient to pass around, and even the sources of the values in a list aren't evaluated until they are used somewhere else.