# Primitives addon

These functions are declared in the following header file.
Link with allegro_primitives.

~~~~c
 #include <allegro5/allegro_primitives.h>
~~~~

## General

### API: al_get_allegro_primitives_version

Returns the (compiled) version of the addon, in the same format as
[al_get_allegro_version].

### API: al_init_primitives_addon

Initializes the primitives addon.

*Returns:*
True on success, false on failure.

See also: [al_shutdown_primitives_addon]

### API: al_shutdown_primitives_addon

Shut down the primitives addon. This is done automatically at program exit,
but can be called any time the user wishes as well.

See also: [al_init_primitives_addon]

## High level drawing routines

High level drawing routines encompass the most common usage of this addon: to
draw geometric primitives, both smooth (variations on the circle theme) and 
piecewise linear. Outlined primitives support the concept of thickness with two
distinct modes of output: hairline lines and thick lines. Hairline lines are
specifically designed to be exactly a pixel wide, and are commonly used for
drawing outlined figures that need to be a pixel wide. Hairline thickness is 
designated as thickness less than or equal to 0. Unfortunately, the exact
rasterization rules for drawing these hairline lines vary from one video card
to another, and sometimes leave gaps where the lines meet. If that matters to
you, then you should use thick lines. In many cases, having a thickness of 1
will produce 1 pixel wide lines that look better than hairline lines. Obviously,
hairline lines cannot replicate thicknesses greater than 1. Thick lines grow 
symmetrically around the generating shape as thickness is increased.

### Pixel-precise output

While normally you should not be too concerned with which pixels are displayed
when the high level primitives are drawn, it is nevertheless possible to 
control that precisely by carefully picking the coordinates at which you draw 
those primitives.

To be able to do that, however, it is critical to understand how GPU cards
convert shapes to pixels. Pixels are not the smallest unit that can be
addressed by the GPU. Because the GPU deals with floating point coordinates,
it can in fact assign different coordinates to different parts of a single 
pixel. To a GPU, thus, a screen is composed of a grid of squares that have width
and length of 1. The top left corner of the top left pixel is located at (0, 0).
Therefore, the center of that pixel is at (0.5, 0.5). The basic rule that 
determines which pixels are associated with which shape is then as follows:
a pixel is treated to belong to a shape if the pixel's center is located in that 
shape. The figure below illustrates the above concepts:

![*Diagram showing a how pixel output is calculated by the GPU given the 
mathematical description of several shapes.*](images/primitives1.png)

This figure depicts three shapes drawn at the top left of the screen: an orange 
and green rectangles and a purple circle. On the left are the mathematical 
descriptions of pixels on the screen and the shapes to be drawn. On the right is
the screen output. Only a single pixel has its center inside the circle, and 
therefore only a single pixel is drawn on the screen. Similarly, two pixels are 
drawn for the orange rectangle. Since there are no pixels that have their 
centers inside the green rectangle, the output image has no green pixels.

Here is a more practical example. The image below shows the output of this code:

~~~~c
/* blue vertical line */
al_draw_line(0.5, 0, 0.5, 6, color_blue, 1);
/* red horizontal line */
al_draw_line(2, 1, 6, 1, color_red, 2);
/* green filled rectangle */
al_draw_filled_rectangle(3, 4, 5, 5, color_green);
/* purple outlined rectangle */
al_draw_rectangle(2.5, 3.5, 5.5, 5.5, color_purple, 1);
~~~~

![*Diagram showing a practical example of pixel output resulting from the 
invocation of several primitives addon functions.*](images/primitives2.png)

It can be seen that lines are generated by making a rectangle based on the 
dashed line between the two endpoints. The thickness causes the rectangle to
grow symmetrically about that generating line, as can be seen by comparing the
red and blue lines. Note that to get proper pixel coverage, the coordinates
passed to the `al_draw_line` had to be offset by 0.5 in the appropriate 
dimensions.

Filled rectangles are generated by making a rectangle between the endpoints
passed to the `al_draw_filled_rectangle`.

Outlined rectangles are generated by symmetrically expanding an outline of a 
rectangle. With a thickness of 1, as depicted in the diagram, this means that an
offset of 0.5 is needed for both sets of endpoint coordinates to exactly line
up with the pixels of the display raster.

The above rules only apply when multisampling is turned off. When multisampling
is turned on, the area of a pixel that is covered by a shape is taken into
account when choosing what color to draw there. This also means that shapes no 
longer have to contain the pixel's center to affect its color. For example,
the green rectangle in the first diagram may in fact be drawn as two (or one)
semi-transparent pixels. The advantages of multisampling is that slanted shapes 
will look smoother because they will not have jagged edges. A disadvantage of
multisampling is that it may make vertical and horizontal edges blurry. While
the exact rules for multisampling are unspecified, and may vary from GPU to 
GPU it is usually safe to assume that as long as a pixel is either completely
covered by a shape or completely not covered, then the shape edges will be 
sharp. The offsets used in the second diagram were chosen so that this is the
case: if you use those offsets, your shapes (if they are oriented the same way
as they are on the diagram) should look the same whether multisampling is 
turned on or off.

### API: al_draw_line

Draws a line segment between two points.

*Parameters:*

* x1, y1, x2, y2 - Start and end points of the line
* color - Color of the line
* thickness - Thickness of the line, pass `<= 0` to draw hairline lines

See also: [al_draw_soft_line]

### API: al_draw_triangle

Draws an outlined triangle.

*Parameters:*

* x1, y1, x2, y2, x3, y3 - Three points of the triangle
* color - Color of the triangle
* thickness - Thickness of the lines, pass `<= 0` to draw hairline lines

See also: [al_draw_filled_triangle], [al_draw_soft_triangle]

### API: al_draw_filled_triangle

Draws a filled triangle.

*Parameters:*

* x1, y1, x2, y2, x3, y3 - Three points of the triangle
* color - Color of the triangle

See also: [al_draw_triangle]

### API: al_draw_rectangle

Draws an outlined rectangle.

*Parameters:*

* x1, y1, x2, y2 - Upper left and lower right points of the rectangle
* color - Color of the rectangle
* thickness - Thickness of the lines, pass `<= 0` to draw hairline lines

See also: [al_draw_filled_rectangle], [al_draw_rounded_rectangle]

### API: al_draw_filled_rectangle

Draws a filled rectangle.

*Parameters:*

* x1, y1, x2, y2 - Upper left and lower right points of the rectangle
* color - Color of the rectangle

See also: [al_draw_rectangle], [al_draw_filled_rounded_rectangle]

### API: al_draw_rounded_rectangle

Draws an outlined rounded rectangle.

*Parameters:*

* x1, y1, x2, y2 - Upper left and lower right points of the rectangle
* color - Color of the rectangle
* rx, ry - The radii of the round
* thickness - Thickness of the lines, pass `<= 0` to draw hairline lines

See also: [al_draw_filled_rounded_rectangle], [al_draw_rectangle]

### API: al_draw_filled_rounded_rectangle

Draws an filled rounded rectangle.

*Parameters:*

* x1, y1, x2, y2 - Upper left and lower right points of the rectangle
* color - Color of the rectangle
* rx, ry - The radii of the round

See also: [al_draw_rounded_rectangle], [al_draw_filled_rectangle]

### API: al_calculate_arc

When `thickness <= 0` this function computes positions of `num_points`
regularly spaced points on an elliptical arc. When `thickness > 0` this
function computes two sets of points, obtained as follows: the first set is
obtained by taking the points computed in the `thickness <= 0` case and
shifting them by `thickness / 2` outward, in a direction perpendicular to the
arc curve. The second set is the same, but shifted `thickness / 2` inward
relative to the arc. The two sets of points are interleaved in the destination
buffer (i.e. the first pair of points will be collinear with the arc center,
the first point of the pair will be farther from the center than the second
point; the next pair will also be collinear, but at a different angle and so
on).

The destination buffer `dest` is interpreted as a set of regularly spaced pairs
of floats, each pair holding the coordinates of the corresponding point on the
arc. The two floats in the pair are adjacent, and the distance (in bytes)
between the addresses of the first float in two successive pairs is `stride`.
For example, if you have a tightly packed array of floats with no spaces
between pairs, then `stride` will be exactly `2 * sizeof(float)`.

Example with `thickness <= 0`:

~~~~c
const int num_points = 4;
float points[num_points][2];
al_calculate_arc(&points[0][0], 2 * sizeof(float), 0, 0, 10, 10, 0, ALLEGRO_PI / 2, 0, num_points);

assert((int)points[0][0] == 10);
assert((int)points[0][1] == 0);

assert((int)points[num_points - 1][0] == 0);
assert((int)points[num_points - 1][1] == 10);
~~~~

Example with `thickness > 0`:

~~~~c
const int num_points = 4;
float points[num_points * 2][2];
al_calculate_arc(&points[0][0], 2 * sizeof(float), 0, 0, 10, 10, 0, ALLEGRO_PI / 2, 2, num_points);

assert((int)points[0][0] == 11);
assert((int)points[0][1] == 0);
assert((int)points[1][0] == 9);
assert((int)points[1][1] == 0);

assert((int)points[(num_points - 1) * 2][0] == 0);
assert((int)points[(num_points - 1) * 2][1] == 11);
assert((int)points[(num_points - 1) * 2 + 1][0] == 0);
assert((int)points[(num_points - 1) * 2 + 1][1] == 9);
~~~~

*Parameters:*

* dest - The destination buffer
* stride - Distance (in bytes) between starts of successive pairs of points
* cx, cy - Center of the arc
* rx, ry - Radii of the arc
* start_theta - The initial angle from which the arc is calculated
* delta_theta - Angular span of the arc (pass a negative number to switch
 direction)
* thickness - Thickness of the arc
* num_points - The number of points to calculate

See also: [al_draw_arc], [al_calculate_spline], [al_calculate_ribbon]

### API: al_draw_pieslice

Draws a pieslice (outlined circular sector).

*Parameters:*

* cx, cy - Center of the pieslice
* r - Radius of the pieslice
* color - Color of the pieslice
* start_theta - The initial angle from which the pieslice is drawn
* delta_theta - Angular span of the pieslice (pass a negative number to switch
    direction)
* thickness - Thickness of the circle, pass `<= 0` to draw hairline pieslice

Since: 5.0.6, 5.1.0

See also: [al_draw_filled_pieslice]

### API: al_draw_filled_pieslice

Draws a filled pieslice (filled circular sector).

*Parameters:*

* cx, cy - Center of the pieslice
* r - Radius of the pieslice
* color - Color of the pieslice
* start_theta - The initial angle from which the pieslice is drawn
* delta_theta - Angular span of the pieslice (pass a negative number to switch
    direction)

Since: 5.0.6, 5.1.0

See also: [al_draw_pieslice]

### API: al_draw_ellipse

Draws an outlined ellipse.

*Parameters:*

* cx, cy - Center of the ellipse
* rx, ry - Radii of the ellipse
* color - Color of the ellipse
* thickness - Thickness of the ellipse, pass `<= 0` to draw a hairline ellipse

See also: [al_draw_filled_ellipse], [al_draw_circle]

### API: al_draw_filled_ellipse

Draws a filled ellipse.

*Parameters:*

* cx, cy - Center of the ellipse
* rx, ry - Radii of the ellipse
* color - Color of the ellipse

See also: [al_draw_ellipse], [al_draw_filled_circle]

### API: al_draw_circle

Draws an outlined circle.

*Parameters:*

* cx, cy - Center of the circle
* r - Radius of the circle
* color - Color of the circle
* thickness - Thickness of the circle, pass `<= 0` to draw a hairline circle

See also: [al_draw_filled_circle], [al_draw_ellipse]

### API: al_draw_filled_circle

Draws a filled circle.

*Parameters:*

* cx, cy - Center of the circle
* r - Radius of the circle
* color - Color of the circle

See also: [al_draw_circle], [al_draw_filled_ellipse]

### API: al_draw_arc

Draws an arc.

*Parameters:*

* cx, cy - Center of the arc
* r - Radius of the arc
* color - Color of the arc
* start_theta - The initial angle from which the arc is calculated
* delta_theta - Angular span of the arc (pass a negative number to switch
    direction)
* thickness - Thickness of the arc, pass `<= 0` to draw hairline arc

See also: [al_calculate_arc], [al_draw_elliptical_arc]

### API: al_draw_elliptical_arc

Draws an elliptical arc.

*Parameters:*

* cx, cy - Center of the arc
* rx, ry - Radii of the arc
* color - Color of the arc
* start_theta - The initial angle from which the arc is calculated
* delta_theta - Angular span of the arc (pass a negative number to switch
    direction)
* thickness - Thickness of the arc, pass `<= 0` to draw hairline arc

Since: 5.0.6, 5.1.0

See also: [al_calculate_arc], [al_draw_arc]


### API: al_calculate_spline

Calculates a Bézier spline given 4 control points. If `thickness <= 0`, then
`num_segments` of points are required in the destination, otherwise twice as
many are needed.  The destination buffer should consist of regularly spaced (by
distance of stride bytes) doublets of floats, corresponding to x and y
coordinates of the vertices.

*Parameters:*

* dest - The destination buffer
* stride - Distance (in bytes) between starts of successive pairs of coordinates
* points - An array of 4 pairs of coordinates of the 4 control points
* thickness - Thickness of the spline ribbon
* num_segments - The number of points to calculate

See also: [al_draw_spline], [al_calculate_arc], [al_calculate_ribbon]

### API: al_draw_spline

Draws a Bézier spline given 4 control points.

*Parameters:*

* points - An array of 4 pairs of coordinates of the 4 control points
* color - Color of the spline
* thickness - Thickness of the spline, pass `<= 0` to draw a hairline spline

See also: [al_calculate_spline]

### API: al_calculate_ribbon

Calculates a ribbon given an array of points. The ribbon will go through all of
the passed points. If `thickness <= 0`, then `num_segments` of points are
required in the destination buffer, otherwise twice as many are needed. 
The destination and the points buffer should consist of regularly spaced
doublets of floats, corresponding to x and y coordinates of the vertices.

*Parameters:*

* dest - Pointer to the destination buffer
* dest_stride - Distance (in bytes) between starts of successive pairs of 
    coordinates in the destination buffer
* points - An array of pairs of coordinates for each point
* points_stride - Distance (in bytes) between starts successive pairs of 
    coordinates in the points buffer
* thickness - Thickness of the spline ribbon
* num_segments - The number of points to calculate

See also: [al_draw_ribbon], [al_calculate_arc], [al_calculate_spline]

### API: al_draw_ribbon

Draws a series of straight lines given an array of points. The ribbon will go
through all of the passed points.

*Parameters:*

* points - An array of coordinate pairs (x and y) for each point
* color - Color of the spline
* thickness - Thickness of the spline, pass `<= 0` to draw hairline spline

See also: [al_calculate_ribbon]

## Low level drawing routines

Low level drawing routines allow for more advanced usage of the addon, allowing
you to pass arbitrary sequences of vertices to draw to the screen. These
routines also support using textures on the primitives with the following
restrictions:

For maximum portability, you should only use textures that have dimensions that 
are a power of two, as not every videocard supports them completely. This 
warning is relaxed, however, if the texture coordinates never exit the
boundaries of a single bitmap (i.e. you are not having the texture repeat/tile).
As long as that is the case, any texture can be used safely. Sub-bitmaps work
as textures, but cannot be tiled.

Some platforms also dictate a minimum texture size, which means that textures
smaller than that size will not tile properly. The minimum size that will work
on all platforms is 32 by 32.

A note about pixel coordinates. In OpenGL the texture coordinate (0, 0) refers
to the top left corner of the pixel. This confuses some drivers, because due to
rounding errors the actual pixel sampled might be the pixel to the top and/or 
left of the (0, 0) pixel. To make this error less likely it is advisable to
offset the texture coordinates you pass to the al_draw_prim by (0.5, 0.5) if you
need precise pixel control. E.g. to refer to pixel (5, 10) you'd set the u and v
to 5.5 and 10.5 respectively.

See also: [Pixel-precise output]

### API: al_draw_prim

Draws a subset of the passed vertex buffer.

*Parameters:*

* texture - Texture to use, pass 0 to use only color shaded primitves
* vtxs - Pointer to an array of vertices
* decl - Pointer to a vertex declaration. If set to NULL, the vertices
      are assumed to be of the ALLEGRO_VERTEX type
* start - Start index of the subset of the vertex buffer to draw
* end - One past the last index of subset of the vertex buffer to draw
* type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind
         of primitive to draw

*Returns:*
Number of primitives drawn

For example to draw a textured triangle you could use:

~~~~c
ALLEGRO_COLOR white = al_map_rgb_f(1, 1, 1);
ALLEGRO_VERTEX v[] = {
   {.x = 128, .y = 0, .z = 0, .color = white, .u = 128, .v = 0},
   {.x = 0, .y = 256, .z = 0, .color = white, .u = 0, .v = 256},
   {.x = 256, .y = 256, .z = 0, .color = white, .u = 256, .v = 256}};
al_draw_prim(v, NULL, texture, 0, 3, ALLEGRO_PRIM_TRIANGLE_LIST);
~~~~

See also:
[ALLEGRO_VERTEX], [ALLEGRO_PRIM_TYPE], [ALLEGRO_VERTEX_DECL], 
[al_draw_indexed_prim]

### API: al_draw_indexed_prim

Draws a subset of the passed vertex buffer. This function uses an index array
to specify which vertices to use.

*Parameters:*

* texture - Texture to use, pass 0 to use only shaded primitves
* vtxs - Pointer to an array of vertices
* decl - Pointer to a vertex declaration. If set to 0, the vtxs are assumed
      to be of the ALLEGRO_VERTEX type
* indices - An array of indices into the vertex buffer
* num_vtx - Number of indices from the indices array you want to draw
* type - A member of the [ALLEGRO_PRIM_TYPE] enumeration, specifying what kind
         of primitive to draw

*Returns:*
Number of primitives drawn

See also:
[ALLEGRO_VERTEX], [ALLEGRO_PRIM_TYPE], [ALLEGRO_VERTEX_DECL], [al_draw_prim]

### API: al_create_vertex_decl

Creates a vertex declaration, which describes a custom vertex format.

*Parameters:*

* elements - An array of ALLEGRO_VERTEX_ELEMENT structures.
* stride - Size of the custom vertex structure

*Returns:*
Newly created vertex declaration.

See also:
[ALLEGRO_VERTEX_ELEMENT], [ALLEGRO_VERTEX_DECL], [al_destroy_vertex_decl]

### API: al_destroy_vertex_decl

Destroys a vertex declaration.

*Parameters:*

* decl - Vertex declaration to destroy

See also:
[ALLEGRO_VERTEX_ELEMENT], [ALLEGRO_VERTEX_DECL], [al_create_vertex_decl]

### API: al_draw_soft_triangle

Draws a triangle using the software rasterizer and user supplied pixel
functions. For help in understanding what these functions do, see the
implementation of the various shading routines in addons/primitives/tri_soft.c.
The triangle is drawn in two segments, from top to bottom. The segments are
deliniated by the vertically middle vertex of the triangle. One of each segment
may be absent if two vertices are horizontally collinear.

*Parameters:*

* v1, v2, v3 - The three vertices of the triangle
* state - A pointer to a user supplied struct, this struct will be passed to
  all the pixel functions
* init - Called once per call before any drawing is done. The three
  points passed to it may be altered by clipping.
* first - Called twice per call, once per triangle segment. It is
  passed 4 parameters, the first two are the coordinates of the initial pixel
  drawn in the segment. 
  The second two are the left minor and the left major steps, respectively.
  They represent the sizes of two steps taken by the rasterizer as it walks
  on the left side of the triangle. From then on, the each step will either
  be classified as a minor or a major step, corresponding to the above
  values.
* step - Called once per scanline. The last parameter is set to 1 if the step
  is a minor step, and 0 if it is a major step.
* draw - Called once per scanline. The function is expected to draw the
  scanline starting with a point specified by the first two parameters
  (corresponding to x and y values) going to the right until it reaches the
  value of the third parameter (the x value of the end point). All coordinates
  are inclusive.

See also: [al_draw_triangle]

### API: al_draw_soft_line

Draws a line using the software rasterizer and user supplied pixel functions.
For help in understanding what these functions do, see the implementation of
the various shading routines in addons/primitives/line_soft.c.
The line is drawn top to bottom.

*Parameters:*

* v1, v2 - The two vertices of the line
* state - A pointer to a user supplied struct, this struct will be passed to
  all the pixel functions
* first - Called before drawing the first pixel of the line. It
  is passed the coordinates of this pixel, as well as the two vertices above.
  The passed vertices may have been altered by clipping.
* step - Called once per pixel. The second parameter is set to 1 if the step is
  a minor step, and 0 if this step is a major step. Minor steps are taken only
  either in x or y directions.
  Major steps are taken in both directions diagonally. In all cases, the the
  absolute value of the change in coordinate is at most 1 in either direction.
* draw - Called once per pixel. The function is expected to draw the pixel at
  the coordinates passed to it.

See also: [al_draw_line]

## Structures and types

### API: ALLEGRO_VERTEX

Defines the generic vertex type, with a 3D position, color and texture
coordinates for a single texture. Note that at this time, the software driver
for this addon cannot render 3D primitives. If you want a 2D only primitive,
set z to 0. Note that you must initialize all members of this struct when
you're using it. One exception to this rule are the u and v variables which can
be left uninitialized when you are not using textures.

*Fields:*

* x, y, z - Position of the vertex (float)
* u, v - Texture coordinates measured in pixels (float)
* color - [ALLEGRO_COLOR] structure, storing the color of the vertex

See also:
[ALLEGRO_PRIM_ATTR]

### API: ALLEGRO_VERTEX_DECL

A vertex declaration. This opaque structure is responsible for describing
the format and layout of a user defined custom vertex. It is created and 
destroyed by specialized functions.

See also:
[al_create_vertex_decl], [al_destroy_vertex_decl], [ALLEGRO_VERTEX_ELEMENT]

### API: ALLEGRO_VERTEX_ELEMENT

A small structure describing a certain element of a vertex. E.g. the
position of the vertex, or its color. These structures are used by the 
al_create_vertex_decl function to create the vertex declaration. For that they
generally occur in an array. The last element of such an array should have the 
attribute field equal to 0, to signify that it is the end of the array.
Here is an example code that would create a declaration describing the 
ALLEGRO_VERTEX structure (passing this as vertex declaration to
al_draw_prim would be identical to passing NULL):

~~~~c
/* On compilers without the offsetof keyword you need to obtain the
 * offset with sizeof and make sure to account for packing.
 */
ALLEGRO_VERTEX_ELEMENT elems[] = {
   {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_3, offsetof(ALLEGRO_VERTEX, x)},
   {ALLEGRO_PRIM_TEX_COORD_PIXEL, ALLEGRO_PRIM_FLOAT_2, offsetof(ALLEGRO_VERTEX, u)},
   {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(ALLEGRO_VERTEX, color)},
   {0, 0, 0}
};
ALLEGRO_VERTEX_DECL* decl = al_create_vertex_decl(elems, sizeof(ALLEGRO_VERTEX));
~~~~

*Fields:*

* attribute - A member of the [ALLEGRO_PRIM_ATTR] enumeration, specifying what
   this attribute signifies
* storage - A member of the [ALLEGRO_PRIM_STORAGE] enumeration, specifying how
   this attribute is stored
* offset - Offset in bytes from the beginning of the custom vertex structure. C
   function offsetof is very useful here.

See also:
[al_create_vertex_decl], [ALLEGRO_VERTEX_DECL], [ALLEGRO_PRIM_ATTR],
[ALLEGRO_PRIM_STORAGE]

### API: ALLEGRO_PRIM_TYPE

Enumerates the types of primitives this addon can draw.

* ALLEGRO_PRIM_POINT_LIST - A list of points, each vertex defines a point

* ALLEGRO_PRIM_LINE_LIST - A list of lines, sequential pairs of vertices define
  disjointed lines

* ALLEGRO_PRIM_LINE_STRIP - A strip of lines, sequential vertices define a
  strip of lines

* ALLEGRO_PRIM_LINE_LOOP - Like a line strip, except at the end the first and
  the last vertices are also connected by a line

* ALLEGRO_PRIM_TRIANGLE_LIST - A list of triangles, sequential triplets of
  vertices define disjointed triangles

* ALLEGRO_PRIM_TRIANGLE_STRIP - A strip of triangles, sequential vertices
  define a strip of triangles

* ALLEGRO_PRIM_TRIANGLE_FAN - A fan of triangles, all triangles share the first
  vertex

### API: ALLEGRO_PRIM_ATTR

Enumerates the types of vertex attributes that a custom vertex may have.

* ALLEGRO_PRIM_POSITION - Position information, can be stored only in
   ALLEGRO_PRIM_SHORT_2, ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_FLOAT_3.

* ALLEGRO_PRIM_COLOR_ATTR - Color information, stored in an [ALLEGRO_COLOR].
   The storage field of ALLEGRO_VERTEX_ELEMENT is ignored

* ALLEGRO_PRIM_TEX_COORD - Texture coordinate information, can be stored only in
   ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_SHORT_2. These coordinates are
   normalized by the width and height of the texture, meaning that the
   bottom-right corner has texture coordinates of (1, 1).

* ALLEGRO_PRIM_TEX_COORD_PIXEL - Texture coordinate information, can be stored
   only in ALLEGRO_PRIM_FLOAT_2 and ALLEGRO_PRIM_SHORT_2. These coordinates are
   measured in pixels.

See also:
[ALLEGRO_VERTEX_DECL], [ALLEGRO_PRIM_STORAGE]

### API: ALLEGRO_PRIM_STORAGE

Enumerates the types of storage an attribute of a custom vertex may be stored
in.

* ALLEGRO_PRIM_FLOAT_2 - A doublet of floats
* ALLEGRO_PRIM_FLOAT_3 - A triplet of floats
* ALLEGRO_PRIM_SHORT_2 - A doublet of shorts

See also:
[ALLEGRO_PRIM_ATTR]

### API: ALLEGRO_VERTEX_CACHE_SIZE

Defines the size of the transformation vertex cache for the software renderer.
If you pass less than this many vertices to the primitive rendering functions
you will get a speed boost. This also defines the size of the cache vertex
buffer, used for the high-level primitives. This corresponds to the maximum
number of line segments that will be used to form them.

### API: ALLEGRO_PRIM_QUALITY

Controls the quality of the approximation of curved primitives (e.g. circles).
Curved primitives are drawn by approximating them with a sequence of line
segments. By default, this roughly corresponds to error of less than half of a
pixel.

