To effectively use DirectPython you should understand what layouts mean in Direct3D. If you look it up from the dictionary you might find something like this:
A structured arrangement of items within certain limits.
In Direct3D layout describes how the data will be interpreted by the runtime. You create layout descriptions so that Direct3D knows how your data is laid out and how to use it. For example you might receive a blob of binary data from some third party library and you want to feed that data to Direct3D. If you know the how the blob is structured you can tell it to Direct3D through a layout description.
A layout description is a simple structure (D3D11_INPUT_ELEMENT_DESC) with 7 members and in DirectPython it is represened as a tuple of seven items. There are two uses for this information. Buffers use it to store and retrieve items stored to them. Layouts describe how to map input data into shaders.
Let’s take an example. You want to feed three dimensional position information for rendering. Each point is represented by three floating point numbers (x, y and z).
description = [
("POSITION", 0, FORMAT_R32G32B32_FLOAT, 0, 0, INPUT_PER_VERTEX_DATA, 0),
]
Semantic name of the element. If you use this description to create a Layout-object this name should be the same in the .fx-file. If this layout is used only with Buffers it does not have any meaning.
Semantic index can be used if there are more than one element with the same semantic name. For example a 4x4 matrix will need four elements to describe it.
Format tells how the element will be interpreted. In this case it consists of three 32-bit floating point numbers.
The input slot from where this element will be read. It is possible to interleave data into multiple Buffers and read data simultaneously (when using instancing for example). Device.setVertexBuffers() is used to bind buffers into these slots.
Offset (in bytes) from the start of the first element to the start of this element. It is common to use D3D11_APPEND_ALIGNED_ELEMENT in here so that correct offsets are calculated automatically. If you have “holes” or other oddities in your data this will be the field to use.
Classs for this element, either INPUT_PER_VERTEX_DATA for normal data or INPUT_PER_INSTANCE_DATA if the data is used for instancing.
When describing instanced data this tells how many instances to draw using the same per-instance data before advancing in the buffer by one element.
The layout above is very simple and most applications use more complex ones. For example adding two floats to represent texture coordinates can be done like this:
description = [
("POSITION", 0, FORMAT_R32G32B32_FLOAT, 0, 0, INPUT_PER_VERTEX_DATA, 0),
("TEXTURE", 0, FORMAT_R32G32_FLOAT, 0, APPEND_ALIGNED_ELEMENT, INPUT_PER_VERTEX_DATA, 0),
]
It is also possible to use other types that floats. See Format-values for some possible choices (not all of them are valid or supported, though).
When pushing data to Direct3D the runtime must know how the data is handled by the input assembler. To do this you must combine a layout description with an Effect pass input signature. This makes sure that data gets correctly read and used. You can re-use the d3d11.InputLayout with other passes if they share the same input signature.
#Input data description.
inputLayoutDesc = [
("POSITION", 0, FORMAT_R32G32B32_FLOAT),
("TEXTURE", 0, FORMAT_R32G32_FLOAT),
]
#Load an effect.
effect = Effect("SomeEffect.fx")
#Create an input layout object which will know what the data
#looks like and how to feed it to the shader. The data
#defined in the .fx-file must match with 'inputLayoutDesc'.
#This input layout is valid with any pass that is compatible
#with first techniques (0) first pass (0).
inputLayout = InputLayout(inputLayoutDesc, effect, 0, 0)