summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api.texi794
1 files changed, 693 insertions, 101 deletions
diff --git a/doc/api.texi b/doc/api.texi
index 490a532..7854b53 100644
--- a/doc/api.texi
+++ b/doc/api.texi
@@ -1074,6 +1074,15 @@ Return the identity quaternion.
@node Easings
@subsection Easings
+Easing functions are essential for animation. Each easing function
+provides a different path to go from an initial value to a final
+value. These functions make an excellent companion to the
+@code{tween} procedure (@pxref{Tweening}). Experiment with them to
+figure out which function makes an animation look the best.
+
+Pro tip: @code{smoothstep} provides nice results most of the time and
+creates smoother animation than using @code{linear}.
+
@deffn {Procedure} linear @var{t}
@end deffn
@@ -1271,7 +1280,6 @@ tasks like rendering a sprite while also providing all of the building
blocks to implement additional rendering techniques.
@menu
-* Rendering Engine:: Rendering state management.
* Textures:: 2D images.
* Sprites:: Draw 2D images.
* Tile Maps:: Draw 2D tile maps.
@@ -1279,100 +1287,13 @@ blocks to implement additional rendering techniques.
* Fonts:: Drawing text.
* Particles:: Pretty little flying pieces!
* Blending and Depth Testing:: Control how pixels are combined.
-* Vertex Arrays:: Create 2D/3D models.
-* Shaders:: Create custom GPU programs.
* Framebuffers:: Render to texture.
-* Viewports:: Restrict rendering to
+* Viewports:: Restrict rendering to a particular area.
+* Rendering Engine:: Rendering state management.
+* GPU Buffers:: Send data to the GPU.
+* Shaders:: Create custom GPU programs.
@end menu
-@node Rendering Engine
-@subsection Rendering Engine
-
-Chickadee defines rendering using a metaphor familiar to Scheme
-programmers: procedure application. A shader (@pxref{Shaders}) is
-like a procedure for the GPU to apply. Shaders are passed arguments:
-A vertex array containing the geometry to render (@pxref{Vertex
-Arrays}) and zero or more keyword arguments that the shader
-understands. Similar to how Scheme has @code{apply} for calling
-procedures, Chickadee provides @code{gpu-apply} for calling shaders.
-
-Additionally, there is some dynamic state that effects how
-@code{gpu-apply} will behave. Things like the current viewport,
-framebuffer, and blend mode are stored as dynamic state because it
-would be tedious to have to have to specify them each time
-@code{gpu-apply} is called.
-
-The following procedures and syntax can be found in the
-@code{(chickadee render)} module.
-
-@deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
- [#:uniform-key @var{uniform-value} ...]
-@deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
- @var{count} [#:uniform-key @var{uniform-value} ...]
-
-Render @var{vertex-array} using @var{shader} with the uniform values
-specified in the following keyword arguments.
-
-While @code{gpu-apply} will draw every vertex in @var{vertex-array},
-@code{gpu-apply*} will only draw @var{count} vertices.
-
-@end deffn
-
-@deffn {Procedure} current-viewport
-Return the currently bound viewport (@pxref{Viewports}).
-@end deffn
-
-@deffn {Procedure} current-framebuffer
-Return the currently bound framebuffer (@pxref{Framebuffers}).
-@end deffn
-
-@deffn {Procedure} current-blend-mode
-Return the currently bound blend mode (@pxref{Blending and Depth
-Testing}).
-@end deffn
-
-@deffn {Procedure} current-depth-test
-Return @code{#t} if depth testing is currently enabled (@pxref{Blending and Depth Testing}).
-@end deffn
-
-@deffn {Procedure} current-texture
-Return the currently bound texture (@pxref{Textures}).
-@end deffn
-
-@deffn {Procedure} current-projection
-Return the currently bound projection matrix (@pxref{Matrices}).
-@end deffn
-
-@deffn {Syntax} with-viewport @var{viewport} @var{body} ...
-Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
-@end deffn
-
-@deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
-Evaluate @var{body} with the current framebuffer bound to
-@var{framebuffer} (@pxref{Framebuffers}).
-@end deffn
-
-@deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
-Evaluate @var{body} with the current blend mode bound to
-@var{blend-mode} (@pxref{Blending and Depth Testing}).
-@end deffn
-
-@deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
-Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
-is @code{#f}, or enabled otherwise (@pxref{Blending and Depth
-Testing}).
-@end deffn
-
-@deffn {Syntax} with-texture @var{texture} @var{body} ...
-Evaluate @var{body} with the current texture bound to @var{texture}
-(@pxref{Textures}).
-@end deffn
-
-@deffn {Syntax} with-projection @var{projection} @var{body} ...
-Evaluate @var{body} with the current projection matrix bound to
-@var{projection} (@pxref{Matrices}).
-@end deffn
-
@node Textures
@subsection Textures
@@ -1815,17 +1736,38 @@ Remove @var{emitter} to @var{particles}
@node Blending and Depth Testing
@subsection Blending and Depth Testing
-@node Vertex Arrays
-@subsection Vertex Arrays
+Rendering a scene often involves drawing layers of objects that
+overlap each other. Blending determines how two overlapping pixels
+are combined in the final image that is rendered to the screen.
+Chickadee provides the following blend modes:
-@node Shaders
-@subsection Shaders
+@itemize
+
+@item @code{replace}
+Use the latest color, ignoring all others.
+
+@item @code{alpha}
+Blend pixels according to the values of their alpha channels. This is
+the most commonly used blend mode and thus is Chickadee's default
+mode.
+
+@item @code{add}
+Add all pixel color values together. The more colors blended
+together, the more white the final color becomes.
+
+@item @code{subtract}
+Subtract all pixel color values. The more colors blended together,
+the more black the final color becomes.
+
+@item @code{multiply}
-Shaders are programs for the GPU to evaluate. They are written in the
-OpenGL Shading Language, or GLSL. Chickadee does not currently
-provide a Scheme-like domain specific language for writing shaders.
-Since shaders must be written in GLSL and not Scheme, they are
-considered an advanced feature.
+@item @code{darken}
+
+@item @code{lighten}
+
+@item @code{screen}
+
+@end itemize
@node Framebuffers
@subsection Framebuffers
@@ -1871,6 +1813,656 @@ The default framebuffer.
@node Viewports
@subsection Viewports
+A viewport represents a subset of the screen (or framebuffer). When
+rendering a frame, the resulting image will only appear within that
+viewport. These aren't often needed, and Chickadee's default viewport
+occupies the entire screen, but there are certain situations where
+they are useful. For example, a split-screen multiplayer game may
+render to two different viewports, each occupying a different half of
+the screen. For information about how to set the current viewport,
+see @code{with-viewport} in @ref{Rendering Engine}.
+
+The @code{(chickadee render viewport)} module provides the following
+API:
+
+@deffn {Procedure} make-viewport @var{x} @var{y} @var{width} @var{height} @
+ [#:clear-color] [#:clear-flags]
+
+Create a viewport that covers an area of the window starting from
+coordinates (@var{x}, @var{y}) and spanning @var{width} @code{x}
+@var{height} pixels. Fill the viewport with @var{clear-color} when
+clearing the screen. Clear the buffers denoted by the list of symbols
+in @var{clear-flags}.
+
+Possible values for @var{clear-flags} are @var{color-buffer},
+@var{depth-buffer}, @var{accum-buffer}, and @var{stencil-buffer}.
+@end deffn
+
+@deffn {Procedure} viewport? @var{obj}
+Return @code{#t} if @var{obj} is a viewport.
+@end deffn
+
+@deffn {Procedure} viewport-x @var{viewport}
+Return the left edge of @var{viewport}.
+@end deffn
+
+@deffn {Procedure} viewport-y @var{viewport}
+Return the bottom edge of @var{viewport}.
+@end deffn
+
+@deffn {Procedure} viewport-width @var{viewport}
+Return the width of @var{viewport}.
+@end deffn
+
+@deffn {Procedure} viewport-height @var{viewport}
+Return the height of @var{viewport}.
+@end deffn
+
+@deffn {Procedure} viewport-clear-color @var{viewport}
+Return the clear color for @var{viewport}.
+@end deffn
+
+@deffn {Procedure} viewport-clear-flags @var{viewport}
+Return the list of clear flags for @var{viewport}.
+@end deffn
+
+@node Rendering Engine
+@subsection Rendering Engine
+
+Chickadee defines rendering using a metaphor familiar to Scheme
+programmers: procedure application. A shader (@pxref{Shaders}) is
+like a procedure for the GPU to apply. Shaders are passed arguments:
+A vertex array containing the geometry to render (@pxref{GPU Buffers})
+and zero or more keyword arguments that the shader understands.
+Similar to how Scheme has @code{apply} for calling procedures,
+Chickadee provides @code{gpu-apply} for calling shaders.
+
+Additionally, there is some dynamic state that effects how
+@code{gpu-apply} will behave. Things like the current viewport,
+framebuffer, and blend mode are stored as dynamic state because it
+would be tedious to have to have to specify them each time
+@code{gpu-apply} is called.
+
+The following procedures and syntax can be found in the
+@code{(chickadee render)} module.
+
+@deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
+ [#:uniform-key @var{uniform-value} ...]
+@deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
+ @var{count} [#:uniform-key @var{uniform-value} ...]
+
+Render @var{vertex-array} using @var{shader} with the uniform values
+specified in the following keyword arguments.
+
+While @code{gpu-apply} will draw every vertex in @var{vertex-array},
+@code{gpu-apply*} will only draw @var{count} vertices.
+@end deffn
+
+@deffn {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
+ @var{n} [#:uniform-key @var{uniform-value} ...]
+@deffnx {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
+ @var{count} @var{n} [#:uniform-key @var{uniform-value} ...]
+
+Render @var{vertex-array} @var{n} times using @var{shader} with the
+uniform values specified in the following keyword arguments.
+
+Instanced rendering is very beneficial for rendering the same object
+many times with only small differences for each one. For example, the
+particle effects described in @ref{Particles} use instanced rendering.
+
+While @code{gpu-apply/instanced} will draw every vertex in
+@var{vertex-array}, @code{gpu-apply*} will only draw @var{count}
+vertices.
+@end deffn
+
+@deffn {Procedure} current-viewport
+Return the currently bound viewport (@pxref{Viewports}).
+@end deffn
+
+@deffn {Procedure} current-framebuffer
+Return the currently bound framebuffer (@pxref{Framebuffers}).
+@end deffn
+
+@deffn {Procedure} current-blend-mode
+Return the currently bound blend mode (@pxref{Blending and Depth
+Testing}).
+@end deffn
+
+@deffn {Procedure} current-depth-test
+Return @code{#t} if depth testing is currently enabled (@pxref{Blending and Depth Testing}).
+@end deffn
+
+@deffn {Procedure} current-texture
+Return the currently bound texture (@pxref{Textures}).
+@end deffn
+
+@deffn {Procedure} current-projection
+Return the currently bound projection matrix (@pxref{Matrices}).
+@end deffn
+
+@deffn {Syntax} with-viewport @var{viewport} @var{body} ...
+Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
+@end deffn
+
+@deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
+Evaluate @var{body} with the current framebuffer bound to
+@var{framebuffer} (@pxref{Framebuffers}).
+@end deffn
+
+@deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
+Evaluate @var{body} with the current blend mode bound to
+@var{blend-mode} (@pxref{Blending and Depth Testing}).
+@end deffn
+
+@deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
+Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
+is @code{#f}, or enabled otherwise (@pxref{Blending and Depth
+Testing}).
+@end deffn
+
+@deffn {Syntax} with-texture @var{texture} @var{body} ...
+Evaluate @var{body} with the current texture bound to @var{texture}
+(@pxref{Textures}).
+@end deffn
+
+@deffn {Syntax} with-projection @var{projection} @var{body} ...
+Evaluate @var{body} with the current projection matrix bound to
+@var{projection} (@pxref{Matrices}).
+@end deffn
+
+@node GPU Buffers
+@subsection GPU Buffers
+
+Alright, let's brush aside all of those pretty high level abstractions
+and discuss what is going on under the hood. The GPU exists as a
+discrete piece of hardware separate from the CPU. In order to make it
+draw things, we must ship lots of data out of our memory space and
+into the GPU. The @code{(chickadee render buffer}) module provides an
+API for manipulating GPU buffers.
+
+In OpenGL terminology, a chunk of data allocated on the GPU is a
+``vertex buffer object'' or VBO. For example, here is a bytevector
+that could be transformed into a GPU buffer that packs together vertex
+position and texture coordinates:
+
+@example
+(use-modules (chickadee render buffer) (srfi srfi-4))
+(define data
+ (f32vector -8.0 -8.0 ; 2D vertex
+ 0.0 0.0 ; 2D texture coordinate
+ 8.0 -8.0 ; 2D vertex
+ 1.0 0.0 ; 2D texture coordinate
+ 8.0 8.0 ; 2D vertex
+ 1.0 1.0 ; 2D texture coordinate
+ -8.0 8.0 ; 2d vertex
+ 0.0 1.0)) ; 2D texture coordinate
+@end example
+
+This data represents a textured 16x16 square centered on the
+origin. To send this data to the GPU, the @code{make-buffer} procedure
+is needed:
+
+@example
+(define buffer (make-buffer data #:stride 16)
+@end example
+
+The @code{#:stride} keyword argument indicates how many bytes make up
+each element of the buffer. In this case, there are 4 floats per
+element: 2 for the vertex, and 2 for the texture coordinate. A 32-bit
+float is 4 bytes in length, so the buffer's stride is 16.
+
+Within a VBO, one or more ``attributes'', as OpenGL calls them, may be
+present. Attributes are subregions within the buffer that have a
+particular data type. In this case, there are two attributes packed
+into the buffer. To provided a typed view into a buffer, the
+@code{make-typed-buffer} is needed:
+
+@example
+(define vertices
+ (make-typed-buffer #:buffer buffer
+ #:type 'vec2
+ #:component-type 'float
+ #:length 4))
+(define texcoords
+ (make-typed-buffer #:buffer buffer
+ #:type 'vec2
+ #:component-type 'float
+ #:length 4
+ #:offset 8))
+@end example
+
+To render a square, the GPU needs to draw two triangles, which means
+we need 6 vertices in total. However, the above buffer only contains
+data for 4 vertices. This is becase there are only 4 unique vertices
+for a square, but 2 of them must be repeated for each triangle. To
+work with deduplicated vertex data, an ``index buffer'' must be
+created.
+
+@example
+(define index-buffer
+ (make-buffer (u32vector 0 3 2 0 2 1)
+ #:target 'index)
+(define indices
+ (make-typed-buffer #:type 'scalar
+ #:component-type 'unsigned-int
+ #:buffer index-buffer))
+@end example
+
+Note the use of the @code{#:target} keyword argument. It is required
+because the GPU treats index data in a special way and must be told
+which data is index data.
+
+Now that the typed buffers representing each attribute have been
+created, all that's left is to bind them all together in a ``vertex
+array object'', or VAO. Vertex arrays associate each typed buffer
+with an attribute index on the GPU. The indices that are chosen must
+correspond with the indices that the shader (@pxref{Shaders}) expects
+for each attribute.
+
+@example
+(define vertex-array
+ (make-vertex-array #:indices indices
+ #:attributes `((0 . ,vertices)
+ (1 . ,texcoords))))
+@end example
+
+With the vertex array created, the GPU is now fully aware of how to
+interpret the data that it has been given in the original buffer.
+Actually rendering this square is left as an exercise to the reader.
+See the @ref{Shaders} section and the @code{gpu-apply} procedure in
+@ref{Rendering Engine} the remaining pieces of a successful draw call.
+Additionally, consider reading the source code for sprites, shapes, or
+particles to see GPU buffers in action.
+
+Without further ado, the API reference:
+
+@deffn {Procedure} make-buffer @var{data} [#:name "anonymous"] @
+ [#:length] [#:offset 0] [#:stride 0] [#:target @code{vertex}] @
+ [#:usage @code{static}]
+
+Upload @var{data}, a bytevector, to the GPU. By default, the entire
+bytevector is uploaded. A subset of the data may be uploaded by
+specifying the @var{offset}, the index of the first byte to be
+uploaded, and @var{length}, the number of bytes to upload.
+
+If @var{data} is @code{#f}, allocate @var{length} bytes of fresh GPU
+memory instead.
+
+@var{target} and @var{usage} are hints that tell the GPU how the
+buffer is intended to be used.
+
+@var{target} may be:
+
+@itemize
+@item @code{vertex}
+Vertex attribute data.
+
+@item @code{index}
+Index buffer data.
+
+@end itemize
+
+@var{usage} may be:
+
+@itemize
+@item @code{static}
+The buffer data will not be modified after creation.
+
+@item @code{stream}
+The buffer data will be modified frequently.
+
+@end itemize
+
+@var{name} is simply an arbitrary string for debugging purposes that
+is never sent to the GPU.
+@end deffn
+
+@deffn {Procedure} buffer? @var{obj}
+Return @code{#t} if @var{obj} is a GPU buffer.
+@end deffn
+
+@deffn {Procedure} index-buffer? @var{buffer}
+Return @code{#t} if @var{buffer} is an index buffer.
+@end deffn
+
+@defvar null-buffer
+Represents the absence of a buffer.
+@end defvar
+
+@deffn {Procedure} buffer-name @var{buffer}
+Return the name of @var{buffer}.
+@end deffn
+
+@deffn {Procedure} buffer-length @var{buffer}
+Return the length of @var{buffer}.
+@end deffn
+
+@deffn {Procedure} buffer-stride @var{buffer}
+Return the amount of space, in bytes, between each element in
+@var{buffer}.
+@end deffn
+
+@deffn {Procedure} buffer-target @var{buffer}
+Return the the intended usage of @var{buffer}, either @code{vertex} or
+@code{index}.
+@end deffn
+
+@deffn {Procedure} buffer-usage @var{buffer}
+Return the intended usage of @var{buffer}, either @code{static} for
+buffer data that will not change once sent to the GPU, or
+@code{stream} for buffer data that will be frequently updated from the
+client-side.
+@end deffn
+
+@deffn {Procedure} buffer-data @var{buffer}
+Return a bytevector containing all the data within @var{buffer}. If
+@var{buffer} has not been mapped (see @code{with-mapped-buffer}) then
+this procedure will return @code{#f}.
+@end deffn
+
+@deffn {Syntax} with-mapped-buffer @var{buffer} @var{body} @dots{}
+Evaluate @var{body} in the context of @var{buffer} having its data
+synced from GPU memory to RAM. In this context, @code{buffer-data}
+will return a bytevector of all the data stored in @var{buffer}. When
+program execution exits this form, the data (including any
+modifications) is synced back to the GPU.
+
+This form is useful for streaming buffers that need to update their
+contents dynamically, such as a sprite batch.
+@end deffn
+
+@deffn {Procedure} make-typed-buffer #:buffer #:type @
+ #:component-type #:length [#:offset 0] [#:divisor] @
+ [#:name "anonymous"]
+
+Return a new typed buffer view for @var{buffer} starting at byte index
+@var{offset} of @var{length} elements, where each element is of
+@var{type} and composed of @var{component-type} values.
+
+Valid values for @var{type} are:
+
+@itemize
+@item @code{scalar}
+single number
+
+@item @code{vec2}
+2D vector
+
+@item @code{vec3}
+3D vector
+
+@item @code{vec4}
+4D vector
+
+@item @code{mat2}
+2x2 matrix
+
+@item @code{mat3}
+3x3 matrix
+
+@item @code{mat4}
+4x4 matrix
+@end itemize
+
+Valid values for @var{component-type} are:
+
+@itemize
+
+@item @code{byte}
+@item @code{unsigned-byte}
+@item @code{short}
+@item @code{unsigned-short}
+@item @code{int}
+@item @code{unsigned-int}
+@item @code{float}
+@item @code{double}
+
+@end itemize
+
+@var{divisor} is only needed for instanced rendering applications (see
+@code{gpu-apply/instanced} in @ref{Rendering Engine}) and represents
+how many instances each vertex element applies to. A divisor of 0
+means that a single element is used for every instance and is used for
+the data being instanced. A divisor of 1 means that each element is
+used for 1 instance. A divisor of 2 means that each element is used
+for 2 instances, and so on.
+@end deffn
+
+@deffn {Procedure} typed-buffer? @var{obj}
+Return @code{#t} if @var{obj} is a typed buffer.
+@end deffn
+
+@deffn {Procedure} typed-buffer->buffer @var{typed-buffer}
+Return the buffer that @var{typed-buffer} is using.
+@end deffn
+
+@deffn {Procedure} typed-buffer-name @var{typed-buffer}
+Return the name of @var{typed-buffer}.
+@end deffn
+
+@deffn {Procedure} typed-buffer-offset @var{typed-buffer}
+Return the byte offset of @var{typed-buffer}.
+@end deffn
+
+@deffn {Procedure} typed-buffer-type @var{typed-buffer}
+Return the data type of @var{typed-buffer}.
+@end deffn
+
+@deffn {Procedure} typed-buffer-component-type @var{typed-buffer}
+Return the component data type of @var{typed-buffer}
+@end deffn
+
+@deffn {Procedure} typed-buffer-divisor @var{typed-buffer}
+Return the instance divisor for @var{typed-buffer}.
+@end deffn
+
+@deffn {Syntax} with-mapped-typed-buffer @var{typed-buffer} @var{body} @dots{}
+
+Evaluate @var{body} in the context of @var{typed-buffer} having its
+data synced from GPU memory to RAM. See @code{with-mapped-buffer} for
+more information.
+@end deffn
+
+@deffn {Procedure} make-vertex-array #:indices #:attributes @
+ [#:mode @code{triangles}]
+
+Return a new vertex array using the index data within the typed buffer
+@var{indices} and the vertex attribute data within @var{attributes}.
+
+@var{attributes} is an alist mapping shader attribute indices to typed
+buffers containing vertex data:
+
+@example
+`((1 . ,typed-buffer-a)
+ (2 . ,typed-buffer-b)
+ ...)
+@end example
+
+By default, the vertex array is interpreted as containing a series of
+triangles. If another primtive type is desired, the @var{mode}
+keyword argument may be overridden. The following values are
+supported:
+
+@itemize
+@item @code{points}
+@item @code{lines}
+@item @code{line-loop}
+@item @code{line-strip}
+@item @code{triangles}
+@item @code{triangle-strip}
+@item @code{triangle-fan}
+@end itemize
+
+@end deffn
+
+@defvar null-vertex-array
+Represents the absence of a vertex array.
+@end defvar
+
+@deffn {Procedure} vertex-array? @var{obj}
+Return @code{#t} if @var{obj} is a vertex array.
+@end deffn
+
+@deffn {Procedure} vertex-array-indices @var{vertex-array}
+Return the typed buffer containing index data for @var{vertex-array}.
+@end deffn
+
+@deffn {Procedure} vertex-array-attributes @var{vertex-array}
+Return the attribute index -> typed buffer mapping of vertex attribute
+data for @var{vertex-array}.
+@end deffn
+
+@deffn {Procedure} vertex-array-mode @var{vertex-array}
+Return the primitive rendering mode for @var{vertex-array}.
+@end deffn
+
+@node Shaders
+@subsection Shaders
+
+Shaders are programs that the GPU can evaluate that allow the
+programmer to completely customized the final output of a GPU draw
+call. The @code{(chickadee render shader)} module provides an API for
+building custom shaders.
+
+Shaders are written in the OpenGL Shading Language, or GLSL for short.
+Chickadee aspires to provide a domain specific language for writing
+shaders in Scheme, but we are not there yet.
+
+Shader programs consist of two components: A vertex shader and a
+fragment shader. A vertex shader receives vertex data (position
+coordinates, texture coordinates, normals, etc.) and transforms them
+as desired, whereas a fragment shader controls the color of each
+pixel.
+
+Sample vertex shader:
+
+@example
+@verbatim
+#version 130
+
+in vec2 position;
+in vec2 tex;
+out vec2 fragTex;
+uniform mat4 mvp;
+
+void main(void) {
+ fragTex = tex;
+ gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
+}
+@end verbatim
+@end example
+
+Sample fragment shader:
+
+@example
+@verbatim
+#version 130
+
+in vec2 fragTex;
+uniform sampler2D colorTexture;
+
+void main (void) {
+ gl_FragColor = texture2D(colorTexture, fragTex);
+}
+@end verbatim
+@end example
+
+This manual will not cover GLSL features and syntax as there is lots
+of information already available about this topic.
+
+One way to think about rendering with shaders, and the metaphor
+Chickadee uses, is to think about it as a function call: The shader is
+a function, and it is applied to some ``attributes'' (positional
+arguments), and some ``uniforms'' (keyword arguments).
+
+@example
+(define my-shader (load-shader "vert.glsl" "frag.glsl"))
+(define vertices (make-vertex-array ...))
+(gpu-apply my-shader vertices #:color red)
+@end example
+
+@xref{Rendering Engine} for more details about the @code{gpu-apply}
+procedure.
+
+Shaders are incredibly powerful tools, and there's more information
+about them than we could ever fit into this manual, so we highly
+recommend searching the web for more information and examples. What
+we can say, though, is how to use our API:
+
+@deffn {Procedure} strings->shader @var{vertex-source} @var{fragment-source}
+Compile @var{vertex-source}, the GLSL code for the vertex shader, and
+@var{fragment-source}, the GLSL code for the fragment shader, into a
+GPU shader program.
+@end deffn
+
+@deffn {Procedure} load-shader @var{vertex-source-file} @
+ @var{fragment-source-file}
+
+Compile the GLSL source code within @var{vertex-source-file} and
+@var{fragment-source-file} into a GPU shader program.
+@end deffn
+
+@deffn {Procedure} make-shader @var{vertex-port} @var{fragment-port}
+Read GLSL source from @var{vertex-port} and @var{fragment-port} and
+compile them into a GPU shader program.
+@end deffn
+
+@deffn {Procedure} shader? @var{obj}
+Return @code{#t} if @var{obj} is a shader.
+@end deffn
+
+@defvar null-shader
+Represents the absence shader program.
+@end defvar
+
+@deffn {Procedure} shader-uniform @var{shader} @var{name}
+Return the metadata for the uniform @var{name} in @var{shader}.
+@end deffn
+
+@deffn {Procedure} shader-uniforms @var{shader}
+Return a hash table of uniforms for @var{shader}.
+@end deffn
+
+@deffn {Procedure} shader-attributes @var{shader}
+Return a hash table of attributes for @var{shader}.
+@end deffn
+
+@deffn {Procedure} uniform? @var{obj}
+Return @code{#t} if @var{obj} is a uniform.
+@end deffn
+
+@deffn {Procedure} uniform-name @var{uniform}
+Return the variable name of @var{uniform}.
+@end deffn
+
+@deffn {Procedure} uniform-type @var{uniform}
+Return the data type of @var{uniform}.
+@end deffn
+
+@deffn {Procedure} uniform-value @var{uniform}
+Return the current value of @var{uniform}.
+@end deffn
+
+@deffn {Procedure} uniform-default-value @var{uniform}
+Return the default value of @var{uniform}.
+@end deffn
+
+@deffn {Procedure} attribute? @var{obj}
+Return @code{#t} if @var{obj} is an attribute.
+@end deffn
+
+@deffn {Procedure} attribute-name @var{attribute}
+Return the variable name of @var{attribute}.
+@end deffn
+
+@deffn {Procedure} attribute-location @var{attribute}
+Return the binding location of @var{attribute}.
+@end deffn
+
+@deffn {Procedure} attribute-type @var{attribute}
+Return the data type of @var{attribute}.
+@end deffn
+
@node Scripting
@section Scripting