In this chapter I shall outline the design of a new RISC OS module that implements a programmer's interface based upon a subset of Silicon Graphics' popular OpenGL graphics system. The subset of commands has been chosen mainly to provide facilities for games developers similar to the pseudo-standard "MiniGL"s found on other platforms, whilst avoiding duplication of existing RISC OS graphics capabilities.
Note that there is an important distinction between the design of my GL module and its functional specification, although within this chapter the boundaries between these concepts are not always clearly defined:
Another programmer may produce a module that conforms to the same functional specification (and hence is compatible with the same client programs), yet operates differently internally. For example, my module currently implements painter's algorithm, so the internal design features lots of buffering. This is not a stipulation of the functional specification, however.
The SWI specifications in this chapter have been adapted from more detailed descriptions in the programmer's guide. For the sake of brevity some of the standard (but dispensable) features of SWI documentation have been omitted:
Conceptually the GL module presents an immediate-mode interface, in that commands are executed in the order that they are issued, and the effects of one command must be fully realised before the effects of subsequent commands.
Unlike 2-D graphics plotting using the VDU drivers, however,
there may be an indeterminate delay between specifying
geometric data to the graphics library and the corresponding
graphics being drawn on the screen. This is used to advantage
by the painter's algorithm implementation, where the delay
would necessarily be infinite if the accumulated data were
not eventually flushed by a call to GL_Finish
.
The GL module maintains a relatively large amount of data on its current state. This state information has a large influence on the effects of most commands, and indeed in some states certain groups of commands are unavailable.
A client program containing errors may get the module into an
indeterminate state such that calling SWIs generates
"Operation illegal in current state" errors. In this
situation the simplest course of action is to reset the
module: As with any other module this can be done by calling
OS_Module 3
, or by typing "*RMReInit
GraphicsLibrary
" at the command line.
As the vertex coordinates specified to GL_Vertex
travel through the graphics pipeline, they are first
transformed to eye (world) coordinates by the current
model-view matrix, then transformed to clip (view volume)
coordinates by the current projection matrix. Clipping may
result in vertices being moved or deleted, before perspective
division and viewport transformation yield screen
coordinates.
An overview of the vertex transformation pipeline
The model-view and projection transformations are controlled
by the GL_Matrix
... set of SWIs.
GL_MatrixMode
controls whether subsequent matrix
commands affect the model-view or projection matrix. For each
matrix mode a stack of matrices is maintained, allowing the
current matrix to be saved with a call to
GL_PushMatrix
and later restored by a corresponding
call to GL_PullMatrix
.
The model-view and projection matrix stacks, current matrices at the top
SWIs such as GL_MultMatrix
,
GL_LoadIdentity
and GL_LoadMatrix
handle
basic matrix operations, whilst others provide a high-level
interface to common geometric transformations such as
rotation, scaling and translation.
Both parallel and perspective projections are supported,
being set up by calls to GL_Ortho
and
GL_Frustum
respectively.
Changes the current matrix and matrix stack used for subsequent matrix operations
R0 = new matrix mode (see table below)
This call changes the current matrix mode so that subsequent
matrix commands affect either the projection matrix or the
model-view matrix. Each matrix mode has its own matrix stack
and current matrix pointer (which may be controlled using
GL_PushMatrix
and GL_PullMatrix
).
Value of R0 | Matrix mode |
0 | Model-view |
1 | Projection |
The current model-view matrix is used to transform object
(local) coordinates to eye (world) coordinates. You will
invariably want to be in model-view matrix mode when calling
SWIs such as GL_Rotate
, GL_Scale
and GL_Translate
.
The current projection matrix is used to transform eye
(world) coordinates to clip (view volume) coordinates. You
will invariably want to be in projection matrix mode when
calling SWIs such as GL_Ortho
or
GL_Frustum
.
Saves the current matrix on the stack and uses a duplicate in subsequent operations
--
This call pushes the matrix stack for the current mode down by one, saving the current matrix and duplicating it in the new matrix at the top of the stack.
Matrix B is pushed onto the stack
As with other other matrix operations, the matrix stack
operated on depends on the current matrix mode (see
GL_MatrixMode
).
Discards the current matrix and restores the previous stacked matrix
--
Pulls the current matrix from the top of the stack
(discarding it), and restores the matrix below (that was
saved by a previous call to GL_PushMatrix
). If
you call GL_PullMatrix
on a matrix stack with
only one entry then the error "Command would cause a stack
underflow" will be returned.
Matrix C is pulled from the stack
As with other other matrix operations, the matrix stack
operated on depends on the current matrix mode (see
GL_MatrixMode
).
Replaces the current matrix with the identity matrix
--
The identity matrix (illustrated below) passes vertex coordinates unchanged through the graphics transformation pipeline. This is a sensible default to which both the model-view matrix and projection matrix are set when the graphic module is first initialised.
This SWI to resets the current matrix to the identity matrix.
Typically you would do this before a fresh sequence of
model-view transformations (with subsequent calls to
GL_Translate
, GL_Rotate
etc.) and before
setting up a new projection matrix by calling
GL_Ortho
or GL_Frustum
.
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Replaces the current matrix with the specified matrix data
R0 = pointer to replacement 4×4 matrix
This SWI replaces the current matrix with a 4× 4 matrix loaded directly from the client program's memory, via a pointer passed in R0. The replacement matrix should be stored in column-major order, which is the opposite of the usual ordering for 2 dimensional arrays used by the C language. An example is given below to illustrate the correct matrix format:
This example matrix would be stored in memory as an array of 16 consecutive values [1, 2, 3, 4, 0.5, 10.5, 0, 0, 0.25, 0, 20.5, 0, 0.1, 0, 0, 40.5]. Each element of the array occupies a 32-bit word, and holds a 2's complement signed value in fixed point q=16 format, meaning that 10.5 would be stored as 10.5*216.
You should try to avoid loading matrices directly where
possible - instead use calls such as
GL_Translate
or GL_Rotate
to set up
transformations and GL_Ortho
or
GL_Frustum
to set up projections. This will make your
code more readable and reduce the burden of parameter
translation for implementations that use a different numeric
format internally.
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Multiplies the current matrix by the specified matrix data
R0 = pointer to 4×4 matrix to multiply by
This call multiplies the current matrix by the specified
matrix, and replaces the current matrix with the product. R0
should point to an array of 16 values, stored in column-major
order. For full details of the matrix format see the
documentation on GL_LoadMatrix
.
If possible you should try to use a combination of named
transformation functions such as GL_Translate
or
GL_Rotate
instead of this call. Not only will
this make your code more readable, but it allows hidden
optimisation of many common transformation operations to be
done rather than literal 4×4 matrix
multiplications.
As with other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Multiplies the current matrix by a matrix that produces an anti-clockwise rotation around the specified axis
R0 = angle of rotation (in degrees)
R1 = x component of vector
R2 = y component of vector
R3 = z component of vector
This call produces an anti-clockwise rotation around an arbitrary axis, the direction of which is specified in R1-R3 as a 3 dimensional vector. The concept of an axis of rotation is illustrated in the diagram below:
Rotation around an axis
The angle passed in R0 is treated as though it wraps around, if it is beyond 360° or less than 0° (e.g. -4° is treated as 356°). However it is better to specify angles in the range 0°-359° if possible, because these can be looked up directly in the internal sine and cosine tables.
Conceptually this SWI sets up the following general rotation
matrix and calls GL_MultMatrix
.
In actuality, however, dedicated rotation routines are used. Particularly optimised routines can be used in cases where the rotation is around a single axis (e.g. any two components of the vector passed to the SWI are 0).
For instance, to do a simple rotation around the z axis only, set the magnitude of both x and y components of the directional vector to 0. The magnitude of the z component is immaterial in this context - any positive value will do.
|
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Multiplies the current matrix by a general scaling matrix
R0 = x scale factor
R1 = y scale factor
R2 = z scale factor (all in fixed point q=16 form, e.g.
units of 1/65536)
This call sets up a matrix that produces a general scaling according to the specified parameters. The current matrix is multiplied by this scaling matrix, and replaced with the product.
Conceptually this SWI sets up the following general scaling
matrix and calls GL_MultMatrix
.
In actuality, however, dedicated scaling routines are used. Particularly optimised routines can be used in cases where the scaling is only in one axis (e.g. any two of the scale factors passed to the SWI are 1× 216).
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Multiplies the current matrix by a general translation matrix
R0 = x component of vector
R1 = y component of vector
R2 = z component of vector (all in fixed point q=16 form,
e.g. units of 1/65536)
This call sets up a matrix that produces a translation by the specified vector.The current matrix is multiplied by this translation matrix, and replaced with the product.
Conceptually this SWI sets up the following general
translation matrix and calls GL_MultMatrix
.
In actuality, however, dedicated translation routines are used. Particularly optimised routines can be used in cases where the translation is only along one axis (e.g. any two components of the vector passed to the SWI are 0).
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
).
Multiplies the current matrix by a matrix that produces a parallel projection
R0 = left edge
R1 = right edge
R2 = bottom edge
R3 = top edge
R4 = near clipping plane
R5 = far clipping plane
This SWI sets up a matrix that produces a parallel projection, to transform coordinates from a defined view volume in 3D world space onto the flat viewport.
The position and dimensions of this parallelpiped view volume are specified by the SWI parameters: R0-R3 give the position and dimensions (in eye coordinates) of the viewport, as mapped to the near clipping plane. R4 and R5 give the distances from the projection reference point ('eye') to the near and far clipping planes, respectively.
If bad parameters are detected, e.g. if or or , then this SWI will return the error "Numeric argument out of range", leaving the current matrix unchanged.
A view volume for a parallel projection is illustrated in the diagram below:
Parallel projection
The projection is 'parallel' because world coordinates are transformed to the view plane along parallel lines. Only orthographic parallel projections are supported (where the projection is perpendicular to the view plane) - you cannot specify an oblique projection.
The distances to the near and far clip planes (e.g. the front and back of the view volume) are used in mapping world coordinates to depth values in a Z-buffer. The specified left, right, top and bottom edges are used in mapping world coordinates to viewport coordinates. Unless the sides of the view volume have a similar aspect ratio to the viewport then graphics will appear 'squashed' or 'stretched' when mapped from 3-D space to the screen.
The transformation matrix created by this SWI according to the given parameters is as follows:
The current matrix is multiplied by this projection matrix,
and the product replaces the existing matrix. You should
probably call GL_LoadIdentity
to flush any
previous projection matrix before calling this SWI.
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
). This mode should almost certainly be
'projection', so that the projection matrix is set up rather
than corrupting the current model-view matrix.
Multiplies the current matrix by a matrix that produces a perspective projection
R0 = left edge
R1 = right edge
R2 = bottom edge
R3 = top edge
R4 = near clipping plane
R5 = far clipping plane
This SWI sets up a matrix that produces a perspective projection, that will transform coordinates from a truncated pyramidal view volume in 3-D world space onto the flat viewport.
The position and dimensions of this frustum view volume are specified by the SWI parameters: R0-R3 give the position and dimensions (in eye coordinates) of the viewport, as mapped to the near clipping plane. R4 and R5 give the distances from the projection reference point ('eye') to the near and far clipping planes, respectively.
If bad parameters are detected, e.g. or or or or , then this SWI will return the error "Numeric argument out of range", leaving the current matrix unchanged.
A view volume for a perspective projection is illustrated in the diagram below:
Perspective projection
Graphics primitives that fall outside the boundary edges of
the view volume (as specified by this command or
GL_Ortho
) are discarded and those partly outside are
clipped.
The specified left, right, top and bottom edges are used in mapping world coordinates to viewport coordinates. Unless the sides of the view volume have a similar aspect ratio to the viewport then graphics will appear 'squashed' or 'stretched' when mapped from 3-D space to the screen.
The distances to the near and far clip planes (e.g. the front
and back of the view volume) are used in mapping world
coordinates to depth values in a Z-buffer. Unlike in an
orthographic projection (see GL_Ortho
), the
distance to the near clipping plane (given in R4) affects the
appearance of projected graphics. The closer the view plane
is to the projection reference point, the more perspective
effects will be emphasised; the difference in size between
near and far objects becomes exaggerated. Conversely, with a
very distant view plane the perspective projection will
become more similar to a parallel projection.
The transformation matrix created by this SWI according to the given parameters is as follows:
The current matrix is multiplied by this projection matrix,
and the product replaces the existing matrix. You should
probably call GL_LoadIdentity
to flush any
previous projection matrix, before calling this SWI.
As with other other matrix operations, the matrix operated on
depends on the current matrix mode (see
GL_MatrixMode
). This mode should almost certainly be
'projection', so that the projection matrix is set up rather
than corrupting the current model-view matrix.
Example:
|
Vertices are sent to the GL module using the
GL_Vertex
SWI to specify object coordinates in 3
dimensions. The current colour and normal vector are
associated with each new vertex as shown in the diagram
below. The way in which geometric primitives are constructed
from vertices is discussed later.
Processing of incoming vertices and association of auxiliary data
Sends a vertex to the GL, with specified coordinates and current auxiliary data
R0 = x coordinate of vertex
R1 = y coordinate of vertex
R2 = z coordinate of vertex
This SWI is part of the system of geometric data
specification. Invoking this SWI outside of a
GL_Begin
/GL_End
pair will result in the
error "Operation illegal in current state".
Calling GL_Vertex
sends a vertex to the GL for
use in primitive assembly, given the three dimensional object
(local) coordinates specified in R0-R2. The new vertex also
picks up the current values of auxiliary vertex data such as
the current colour and normal vector (see
GL_Colour
and GL_Normal
).
The role of a given vertex in primitive construction is
dictated by the mode value passed to GL_Begin
at
the beginning of geometry specification. An individual vertex
may or may not spawn a graphics primitive, depending on the
current mode and state. For further details see the
documentation on GL_Begin
.
To reduce the number of calls required to specify a sequence
of vertices and their auxiliary data you can also specify an
array of vertex coordinates to be read sequentially - see
GL_VertexPointer
.
Sets the current colour, as used in associating auxiliary data with vertices
R0 = palette entry (BBGGRR00 24-bit colour word)
Vertex colours are specified in terms of red, green and blue components, with 8 bits of accuracy for each. Conceptually this gives 16.7 million possible colours, although the colours actually displayed are only the best approximation in the current screen mode and palette.
Format of a palette entry
The RGB values are packed into a 32-bit colour word in the standard 'palette entry' format used by other RISC OS components such as ColourTrans and the colour picker. For compatibility with future versions of the GL module you should set the bottom 8 bits of the palette entry to zero, since these are likely to be used for an alpha (transparency) value.
The graphics library maintains a current RGB colour (initial
value [255,255,255] e.g. white) which may be changed by
calling this SWI. Like other auxiliary vertex data, the
current colour is immediately associated with each vertex
specified using GL_Vertex
or
GL_ArrayElement
and may be altered for subsequent
vertices.
To reduce the number of calls required to specify a sequence
of vertices and their auxiliary data you can also specify an
array of colour data to be read sequentially - see
GL_ColourPointer
.
Sets the current normal, as used in associating auxiliary data with vertices
R0 = x component of vector
R1 = y component of vector
R2 = z component of vector
A normal is a three dimensional vector (specified as x, y, z components) that is used in lighting calculations for a vertex23. Rather than automatically calculating a normal vector perpendicular to each polygon surface, normals are associated with individual vertices.
The graphics library maintains a current normal vector
(initial value [0,0,1]) which may be changed by calling this
SWI. Like other auxiliary vertex data, the current normal is
immediately associated with each vertex specified using
GL_Vertex
or GL_ArrayElement
and
may be altered for subsequent vertices.
Illustration of the normal vector [3,3,1]
To reduce the number of calls required to specify a sequence
of vertices and their auxiliary data you can also specify an
array of normal vectors to be read sequentially - see
GL_NormalPointer
.
The basic method of specifying object geometry is to send
vertex data to the GL between calls to GL_Begin
and GL_End
. Vertex coordinates are specified by
calling GL_Vertex
, and auxiliary data by
GL_Normal
and GL_Colour
. The
interpretation of this sequence of vertex data and the type
of graphics primitives produced is governed by the current
primitive construction mode, as specified to
GL_Begin
.
It is common for objects to have vertices that are shared by more than one edge. In order to economise on multiple specification and transformation of these shared vertices, various of the construction modes produce interconnected primitives. The following diagram illustrates sharing of vertices between triangle primitives in triangle strip mode:
The order in which vertices are specified is extremely important. The diagrams below illustrate the correspondence between order of vertex specification and output primitives produced, for different primitive construction modes.
Primitive construction modes | ||||
1) Connected line strip | 2) Connected line loop | 3) Individual line segments | 5) Connected triangle strip | |
6) Connected triangle fan | 7) Separate triangles | 8) Connected quadrilateral strip | 9) Separate quadrilaterals |
Note that the order of vertex specification (as indicated by the vertex numbering) does not necessarily correspond to the direction of the arrowed lines, which show the 'direction' of the edges produced (e.g. the internal ordering of corner vertices).
Polygon edges must be in clockwise orderwhen looking at the 'front' face, or else the surface will be treated as back-facing and culled.
For individual polygons (separate quads or separate triangles) this simply means that vertices should be specified in clockwise order - for more complex construction modes you must refer to the diagrams above. All the polygons illustrated are front-facing.
Opening command in Begin/End paradigm of primitive construction
R0 = primitive construction mode (see table below)
All geometric objects are specified to the graphics library
as a number of vertices (specified by calls to
GL_Vertex
) enclosed between calls to to this SWI and
GL_End
. The construction mode passed in R0
determines how graphics primitives are produced from the
sequence of input vertices:
Value of R0 | Primitive construction mode |
0 | Individual points |
1 | Connected line strip |
2 | Connected line loop |
3 | Individual line segments |
4 | Reserved for future expansion |
5 | Connected triangle strip |
6 | Connected triangle fan |
7 | Separate triangles |
8 | Connected quadrilateral strip |
9 | Separate quadrilaterals |
Other values of R0 are reserved for future expansion, and attempts to use them will result in an "ENUM argument out of range" error.
Only commands that specify vertices (GL_Vertex
,
GL_ArrayElement
) or associated data
(GL_Colour
, GL_Normal
) are legal
between calling this SWI and the corresponding call to
GL_End
. Attempts to call other graphics library SWIs
will result in the error "Operation illegal in current
state", as will calling this SWI where GL_Begin
has been called previously without any corresponding call to
GL_End
.
Closing command in Begin/End paradigm of primitive construction
--
This SWI is part of the system of geometric data
specification - it signals the end of primitive construction.
Calling this SWI without having previously called
GL_Begin
will result in the error "Operation illegal
in current state".
Having called GL_End
, it once more becomes legal
to call SWIs not connected with primitive construction - e.g.
to change the model-view matrix for a different object.
Because the Begin/End method of geometry specification can be
quite costly in terms of the overhead of making multiple SWI
calls, an alternative method of primitive specification is
also provided: Vertex coordinates and associated data can be
stored in vertex arrays supplied by the client. The location
and format of these arrays can be set to one of various
predefined configurations by calling
GL_InterleavedArrays
or separately by calling
GL_VertexPointer
, GL_ColourPointer
and
GL_NormalPointer
. Vertices can be transferred
from the arrays individually by calling
GL_ArrayElement
or sequentially by calling
GL_DrawArrays
and GL_DrawElements
. Again,
the production of graphics primitives from vertices is
controlled by the current primitive construction mode.
A generic command for enabling various graphics library features
R0 = feature to enable (see table below)
Together with GL_Disable
, this call allows
client applications a generic method of controlling the
graphics library. The feature to be enabled depends upon the
value passed in R0:
Value of R0 | Meaning |
---|---|
0 | Reserved for future expansion |
1 | Colours vertex array |
2 | Coordinates vertex array |
3 | Normals vertex array |
4 | Reserved for future expansion |
5 | Reserved for future expansion |
6 | Flat shading of polygons |
Other values of R0 are reserved for future expansion, and will produce an "ENUM argument out of range" error in current versions of the graphics library.
Specific vertex arrays must be enabled using this SWI before
calls to GL_ArrayElement
,
GL_DrawArrays
or GL_DrawElements
will
transfer data from those arrays for primitive specification.
Vertex arrays may also be automatically enabled/disabled by
GL_InterleavedArrays
.
If 'flat shading' is turned on then all vertices of a primitive are assigned the colour of the vertex that caused that primitive to be spawned (i.e. the third vertex of a triangle, the fourth of a quadrilateral etc.) Thus the colour of the rasterised surface is uniform (or 'flat'), rather than being the result of interpolation between the colours of different vertices.
A generic command for disabling various graphics library features
R0 = feature to disable (see GL_Enable
)
Together with GL_Enable
, this call allows client
applications a generic method of controlling the graphics
library. The feature to be disabled depends upon the value
passed in R0 (see table of R0 values for
GL_Enable
).
Specifies the location and organisation of an array of vertex coordinates
R0 = data type of array values (see table)
R1 = stride between array elements (in bytes)
R2 = pointer to first array element
This call specifies the location and organisation of an array
of vertex coordinates, for subsequent use in all vertex array
SWIs such as GL_ArrayElement
,
GL_DrawArrays
and GL_DrawElements
.
The value passed in R0 indicates the type of values in the coordinates array:
Value of R0 | Meaning |
---|---|
3 | Signed bytes |
4 | Signed 16-bit integers |
5 | Signed 32-bit integers (word aligned) |
Other values of R0 are reserved for future expansion, and attempts to use them will result in an "ENUM argument out of range" error.
The 'stride' parameter passed in R1 is the number of bytes
between each element in the vertex array. The stride is
variable in order to allow the coordinate array to be
interleaved with other vertex arrays (see
GL_InterleavedArrays
).
Before values can be read from a coordinate array specified
using this SWI, the coordinate array must be enabled by
calling GL_Enable,2
.
Specifies the location and organisation of an array of colour data
R0 = data type of array values (see table)
R1 = stride between array elements (in bytes)
R2 = pointer to first array element
This call specifies the location and organisation of an array
of RGB colours, for subsequent use in all vertex array SWIs
such as GL_ArrayElement
,
GL_DrawArrays
and GL_DrawElements
.
The colours in the array pointed to by R2 must be stored in
the same packed 32-bit word 'palette entry' format as that
described in the documentation on GL_Colour
. For
future compatibility a value of 0 should be passed in R0 as
the 'data type'.
The 'stride' parameter passed in R1 is the number of bytes
between each element in the normal array. The stride is
variable in order to allow the colour array to be interleaved
with other arrays (see GL_InterleavedArrays
).
Before values can be read from a colour array specified using
this SWI, the colour array must be enabled by calling
GL_Enable,1
.
Specifies the location and organisation of an array of normal vector data
R0 = data type of array values (see table)
R1 = stride between array elements (in bytes)
R2 = pointer to first array element
This call specifies the location and organisation of an array
of normal vectors, for subsequent use in all vertex array
SWIs such as GL_ArrayElement
,
GL_DrawArrays
and GL_DrawElements
.
The value passed in R0 indicates the type of values in the normal array:
Value of R0 | Meaning |
---|---|
3 | Signed bytes |
4 | Signed 16-bit integers |
5 | Signed 32-bit integers (word aligned) |
Other values of R0 are reserved for future expansion, and attempts to use them will result in an "ENUM argument out of range" error.
The 'stride' parameter passed in R1 is the number of bytes
between each element in the normal array. The stride is
variable in order to allow the normal array to be interleaved
with other arrays (see GL_InterleavedArrays
).
Before values can be read from a normal array specified using
this SWI, the normal array must be enabled by calling
GL_Enable,3
.
Efficiently initialises the arrays of vertex data to pre-defined configurations
R0 = format of interleaved array data (see below)
R1 = stride between array elements (in bytes)
R2 = pointer to interleaved arrays
This call efficiently initialises the arrays of vertex data to one of a number of pre-defined configurations:
R0 | Element size | Interleaved arrays format |
0 | 12 bytes | 3 words: [x coord, y coord, z coord] |
1 | 8 bytes | 3 shorts: [x coord, y coord, z coord] |
2 | 16 bytes | 4 words: [BGR colour, x coord, y coord, z coord] |
3 | 12 bytes | 1 word, 3 shorts: [BGR colour, x coord, y coord, z coord] |
4 | 24 bytes | 6 words: [normal x, y, z, coordinates x, y, z] |
5 | 12 bytes | 6 shorts: [normal x, y, z, coordinates x, y, z] |
6 | 28 bytes | 7 words: [BGR colour, normal x, y, z, coordinates x, y, z] |
7 | 16 bytes | 1 word, 6 shorts: [BGR colour, normal x, y, z, coordinates x, y, z] |
Other values of R0 are reserved for future expansion, and attempts to use them will result in an "ENUM argument out of range" error. Element sizes marked with have been rounded up so that subsequent entries are word aligned.
The 'stride' parameter passed in R1 is the number of bytes
between each element in the interleaved arrays (e.g. the
second parameter passed to GL_ColourPointer
GL_VertexPointer
and
GL_NormalPointer
) . If the value of R1 is 0 then the
stride is taken from the element size given in the table
above.
As well as setting the colour/normal/coordinate array
pointers depending on the specified interleaved array format,
this SWI also enables or disabled the relevant arrays as
though GL_Enable
/GL_Disable
had
been called. In summary, the effect of the command
|
is equivalent to the effect of the following command sequence24:
|
Defines a vertex by transferring a single element from every enabled array
R0 = element index
This SWI is part of the system of geometric data
specification. Invoking this SWI outside of a
GL_Begin
/GL_End
pair will result in the
error "Operation illegal in current state".
Calling GL_ArrayElement
defines a vertex for use
in primitive assembly, by transferring a single element from
each enabled array (coordinate/normal/colour). The array
element to transfer is specified by the index passed in R0.
If the colour and normal arrays are enabled then the current
vertex colour and normal are set first, as though
GL_Colour
and GL_Normal
had been called
for the specified element from each array. Then, if the
vertex array is enabled, it is as though
GL_Vertex
were called with the coordinates transferred
from the equivalent vertex array element, and the auxiliary
normal and colour.
For details of vertex specification and subsequent processing
see the documentation on GL_Begin
and
GL_Vertex
.
Constructs a sequence of primitives using array elements in a specified range
R0 = primitive construction mode (see GL_Begin
)
R1 = index of first array element
R2 = number of elements in range
This call constructs a sequence of geometric primitives using vertex array elements in the specified range, taken from those of those coordinate/colour/normal arrays that are enabled.
The value passed in R0 for primitive construction mode is
interpreted in exactly the same way as the mode parameter to
GL_Begin
. For details of primitive construction
modes see the documentation on that SWI.
Conceptually, the effect of the command
|
is the same as the effect of the following command sequence:
|
However, calling GL_DrawArrays
is considerably
more efficient than the client program code given above,
because the SWI calling overhead of invoking
GL_ArrayElement
many times over is eliminated. Use of
this SWI also makes client programs more succinct.
Constructs a sequence of primitives using only those vertex array elements specified by an associated array of indices
R0 = primitive construction mode (see GL_Begin
)
R1 = number of indices
R2 = data type of array of indices (see table)
R3 = pointer to array of indices
This SWI constructs a sequence of geometric primitives using only those elements of the coordinate/colour/normal arrays that are specified in the array of indices pointed to by R3. The number of indices to read from this index array is passed in R1, and the numeric type of the index values is passed in R2:
Value of R2 | Meaning |
---|---|
0 | Unsigned bytes |
1 | Unsigned 16-bit integers |
2 | Unsigned 32-bit integers (word aligned) |
Other values of R2 are reserved for future expansion, and attempts to use them will result in an "ENUM argument out of range" error.
As with the SWIs GL_Begin
and
GL_DrawElements
, R0 contains the mode of primitive
construction to be used in processing the resultant sequence
of vertices. For full details of mode values for this
parameter see the documentation on GL_Begin
.
Conceptually, the effect of the command
|
is the same as the effect of the following command sequence25:
|
Like GL_DrawArrays
, this SWI has been provided
to make client programs more succinct, and to economise on
the calling overhead that would inevitably be incurred by
invoking GL_ArrayElement
many times over, as
shown in the program code above.
The GL module will integrate with the existing graphics system as far as possible, in that (like the Font Manager and Draw module) it uses the VDU drivers' coordinate system and graphics origin where appropriate, and does not render outside the boundaries of the current graphics window.
All screen modes with colour depths of 8 bits per pixel or greater will be supported, at any pixel resolution. Attempting to render to 1/2/4bpp modes will generate the error "Cannot plot in this screen mode". In any case, since a 24-bit colour system is used both for colour specification and internally (old-style GCOLs are not supported), colour reproduction in such screen modes would probably be very poor.
The raster subsystem of the library will support points and plain or gouraud shaded triangles and lines. In future versions it is intended to extend these basic facilities to include texture mapping and other advanced rendering options.
Specifies a window within which graphics output will be drawn
R0 = x coordinate of left edge
R1 = y coordinate of bottom edge
R2 = width of viewport
R3 = height of viewport
The viewport is a rectangular area of the screen to which the GL will output graphics. By default it occupies the whole screen area but you can call this SWI to alter its position and dimensions. The parameters to this call are interpreted as OS coordinates relative to the current graphics origin.
Upon mode change the GL viewport is reset so that it occupies the whole screen once more.
Transformed coordinates are scaled to fill the current
viewport, so radically changing the shape of the viewport
compared to the shaped of the view volume (as defined by
GL_Ortho
or GL_Frustum
) will result
in stretched or squashed images.
It is important to understand that the graphics library's viewport is a completely separate entity from the VDU drivers' graphics window. Whereas the graphics window is a clipping window, the GL viewport is a positional window that controls the transformation to screen coordinates (more analogous, in fact, to the VDU graphics origin).
Only the shaded area will be painted
Most of the time you will want them to occupy the same area. However, if you were to define the graphics window and GL viewport to occupy non-overlapping areas of the screen then no visible output would be generated.
Note: As with the VDU drivers' graphics window, changing the
graphics origin subsequent to calling
GL_Viewport
(e.g. using VDU 29
) does not
affect the position of the viewport on the screen.
Does not return until all previous commands have been completed
--
This call causes the effects of all previous commands to be fully realised, causing any buffered graphics to be painted to the screen. It does not return control to the client program until this has taken place.
Calling GL_Finish
may cause a large amount of
pending work to be done, or on an immediate-effect system it
may return immediately. When using painter's algorithm (see
*GLDepthMode
), all graphics plotting is
delayed until this SWI is called. In general, therefore,
client programs should not assume that any graphics
have been plotted until they call GL_Finish
.
After calling GL_Finish
the graphics library
starts a 'clean sheet', in that the rasterisation of
primitives subsequently specified is unaffected by previously
specified primitives. In 'painter
' depth mode
this implies an empty render buffer, whilst in
'zbuffer
' mode it implies clearing the
z-buffer26.
Integral to the design of the GL module is the fact that it should be possible to multiply-instantiate it, since this will be the recommended method for applications running under the Window Manager to implement private rendering contexts.
To create a new instantiation, a client program calls the
standard OS_Module 14
SWI with a unique name for
its instantiation. Whenever control is returned to the client
program via Wimp_Poll
, it should call
OS_Module 16
to set its own as the currently preferred
instantiation. On exit or in the event of a fatal error, it
is the client's responsibility to ensure that it kills its
private GL instantiation (using OS_Module 4
).
The following example BASIC program illustrates these points, as well as a method of ensuring that each client's private instantiation has a unique name:
|
23 Since lighting calculations are not yet supported in this version of the graphics library, the usefulness of this SWI at the present time is moot.
24 It
is assumed that interleaved_arrays%
points to a
block of memory in the format indicated by the '7' parameter
passed to GL_InterleavedArrays
in R0.
25 It
is assumed that indices%
points to a block of
memory containing unsigned integer values, as indicated by
the the '2
' parameter passed to
GL_DrawElements
. The indices cannot be stored in a
true BASIC array, since array references are illegal as SWI
parameters.
26 In
clearing the z-buffer, the GL_Finish
SWI acts as
an amalgam of the OpenGL commands
glClearDepth(1.0)
and
glClear(DEPTH_BUFFER_BIT)
, as well as the obvious
parallel to glFinish()
.