Previous: Working with external data, Up: Direct Layer


2.3 Diving into 3D graphics

Apart from the elementary support for images, SLAYER also allows to use OpenGL display context and exports some of the OpenGL/GLU procedures.

In order to use it, SLAYER needs to operate in 3d mode. This can be achieved by running it with -e3d or --extension 3d command line argument, provided that SLAYER has been built with OpenGL support. It is also possible to compile SLAYER so that it runs in 3d mode by default.

To recognise whether or not the 3d mode is available, one can check for the presence of slayer-3d-available symbol within cond-expand form (srfi-0). Furthermore, if 3d mode is enabled, the slayer-3d is provided.

If you're not familiar with the OpenGL library, I recommend you to read at least the first three chapters of the OpenGL Programming Guide, also known as The Red Book1.

Note, that programming in SLAYER differs in a few ways from the raw OpenGL API. Firstly, many OpenGL tutorials use “glBegin”, “glEnd”, “glVertex*” and similar procedures. SLAYER does not support them. Instead, it forces you to use its wrappers for “glVertexPointer”, “glColorPointer”, “glDrawElements” and so on, which makes it a little bit more difficult for beginners, but results in a more concise code. (There are also higher level interface functions available in (extra 3d) and (widgets 3d) modules)

Secondly, because of Guile's more informative data types, it is unnecessary to maintain so many variants of the same procedure (like “glColor3f”, “glColor4f”, “glColor3u”, “glColor4i”) – SLAYER chooses the appropreate variant depending on the type of the argument.

Thirdly, OpenGL doesn't allow to choose to perform operations on the projection matrix stack: only modelview matrix is available to the procedures like “push-matrix!”, “pop-matrix!” or “multiply-matrix!”; the “glMatrixMode” procedure is unavailable to the programmer, because I didn't find that useful at all.

— Procedure: multiply-matrix! M

Multiply current modelview matrix by 4x4 uniform array M containing floats or doubles.

— Procedure: push-matrix!

Push current modelview matrix on the matrix stack.

— Procedure: pop-matrix!

Pop modelview matrix from the stack.

— Procedure: load-identity!

Set current modelview matrix to identity.

— Procedure: translate-view! vector

Add a translation vector of 3 numbers to current modelview matrix.

— Procedure: rotate-view! quaternion

Rotate current matrix by quaternion. Quaternions are represented by pairs, whose first element is the real scalar, and second – the imaginary vector, but this representation may change in the future2.

— Procedure: scale-view! x [y] [z]

Scale current view by given factor. If only x is given, the view is scaled uniformly along all the axes. If x and y are given, z defaults to 1.0. Otherwise each direction is scaled according x, y and z parameters.

— Procedure: set-viewport! x y w h

Set left upper corner of viewport to (x, y) and its dimensions to (w, h). Note that this differs from OpenGL's viewport, because the origin is the upper left corner, and not in the lower left.

— Procedure: current-viewport

Return a list (x y w h) describing the current viewport. Again, origin is located in the upper left corner, contrary to OpenGL's convention.

— Procedure: set-perspective-projection! fovy [aspect] [near] [far]

Set the projection matrix to calculate perspective projection, where horizontal field of view is specified with fovy. If aspect isn't given, it is calculated according to current viewport, to preserve natural aspect ratio; the near clipping plane defaults to 0.1, and far – to 1000.0.

— Procedure: set-orthographic-projection! left right bottom top [near] [far]

Sets the projection matrix to calculate ortographic projection. If near and far not given, they default to -1.0 and 1.0, respectively.

— Procedure: world->screen/coordinates x y z modelview projection viewport

Given real numbers x, y and z, modelview and projection matrices (represented as 2D uniform f32/f64 arrays) and a viewport list of form (x y w h), return the corresponding list (x' y' z') of point (x y z) expressed in screen coordinates (where z' is the depth buffer value)

— Procedure: screen->world/coordinates x y z modelview projection viewport

Given real numbers x, y and z, modelview and projection matrices (represented as 2D uniform f32/f64 arrays) and a viewport list of form (x y w h), return a uniform vector #f64(x' y' z') of point (x y z) expressed world coordinates.

— Procedure: set-vertex-array! array

Sets current vertex pointer to the two dimensional uniform array of vertices to use it with the draw-faces! procedure. The first dimension of the array specifies the number of vertices, and the second – the number of coordinates (from 2 to 4), so for instance if array is #2f32((0 0 0)(1 1 1)), it will be interpreted as an array containing two three-dimensional vertices: (0, 0, 0) and (1, 1, 1). The uniform array can be of any real type, so it can be either f32, f64, s32, u32, s16, u16, s8 or u8. This procedure enables GL_VERTEX_ARRAY client state.

— Procedure: set-color-array! array

Sets current color pointer to the two-dimensional uniform array of color parameters, that can either have 3 or 4 parameters (the fourth value will be interpreted as alpha channel). The remaining notes from set-vertex-array! apply here as well (mutatis mutandis).

— Procedure: set-normal-array! array

Sets current normal pointer to the two-dimensional uniform array of normal vectors. The vectors must be three-dimensional. The remaining notes from set-vertex-array! apply here as well (mutatis mutandis).

— Procedure: set-texture-coord-array! array

I implemented this procedure, because it was similar to the ones above, but I really don't know what it does. It has never been used nor tested, so if you would like to use it, I wish you all best!

— Procedure: draw-faces! type indices

Draws vertices from the array set using set-vertices-array!, interpreted depending on the value of the type parameter, in the order specified in the uniform array of integer indices (which can be either u8, u16 or u32, and the dimension of which is irrelevant). The type is a symbol that can have one of the following values: points, lines, line-strip, line-loop, triangles, triangle-strip, triangle-fan, quads, quad-strip, polygon (consult OpenGL reference for details).

— Procedure: forget-array! type

Forget a pointer to the array specified in type, so that draw-faces! won't take it into consideration. Possible values of type are the following symbols: vertex-array, color-array, texture-coord-array, normal-array.

— Procedure: set-color! color

Sets the current display color to color, which can either be a uniform vector containing three or four elements, or an integer, interpreted as in the rectangle function from (slayer image).

— Procedure: z-index x y

Returns the z-index of the point at screen coordinates (x y)

— Procedure: set-display-index! value

Set the display index to value. Henceforth, all the objects drawn to 3d scene will be drawn with that index. The index can be the acquired using the display-index procedure. It is useful if one wishes to decide which object was drawn on the screen to e.g. select it using the mouse pointer. The value must be an integer in range between 0 and (max-display-index) (which is currently 254)

— Procedure: display-index x y

Returns the display index of object at position (x y), or #f if there's no object

— Procedure: max-display-index

Returns the maximum value that can be used as display index in the set-display-index! procedure (currently it's 254).

— Procedure: make-light-

Allocate new light. Once the light is allocated, various properties can be set using set-light-property! procedure. When the light is no longer needed, it is desirable to remove it using remove-light!.

— Procedure: remove-light! light

Remove light allocated by make-light- procedure (or its derivatives). It is desirable to remove lights in the opposite order to their allocation order.

— Procedure: set-light-property! light property value

Set the light's property to value. The supported properties (symbols) are similar to parameters of glLightf*, but the 'position and 'direction parameters differ slightly.

*property* *value type* *description*
'ambient #f32(r g b a) ambient intensity
'diffuse #f32(r g b a) diffuse intensity
'specular #f32(r g b a) specular intensity
'position #f32(x y z) or #f light position; if #f, then the light is directional
'direction #f32(x y z) direction of light
'cutoff real spotlight cutoff angle in degrees (for positional lights). The value of 180.0 causes spherical, non-directiona light.
'exponent real
'constant-attenuation real
'linear-attenuation real
'quadratic-attenuation real

I realize that the above list of procedures might be insufficient for certain purposes. If you notice that an essential procedure is lacking here, don't hesitate to let me know about it, and we can try to work out a solution.


Przypisy

[1] http://www.glprogramming.com/red/

[2] To find out more about how quaternions can be used to represent rotations in the 3d space, see e.g. http://www.genesis3d.com/~kdtop/Quaternions-UsingToRepresentRotation.htm