diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api.texi | 1088 | ||||
-rw-r--r-- | doc/chickadee.texi | 55 |
2 files changed, 743 insertions, 400 deletions
diff --git a/doc/api.texi b/doc/api.texi index d435a3b..6a1361d 100644 --- a/doc/api.texi +++ b/doc/api.texi @@ -1,7 +1,7 @@ @menu * Kernel:: The fundamental components. * Math:: Linear algebra, spatial partitioning, and more. -* Graphics:: Eye candy. +* Graphics:: 2D and 3D rendering. * Audio:: Make some noise. * Scripting:: Bringing the game world to life. @end menu @@ -16,7 +16,6 @@ game loop and desktop environment interaction. * The Game Loop:: The core event loop. * Input Devices:: Mouse, keyboard, controller input. * Window Manipulation:: Inspect and modify the graphical window. -* Live Coding:: Tips for building games from the REPL. @end menu @node The Game Loop @@ -516,43 +515,6 @@ Enable or disable fullscreen mode for @var{window}. If it is enabled. @end deffn - -@node Live Coding -@subsection Live Coding - -One of the biggest appeals of any Lisp dialect is the ability to use -the ``read-eval-print loop'' (REPL for short) to build programs -iteratively and interactively while the program is running. However, -programs that run in an event loop and respond to user input (such as -a video game) require special care for this workflow to be pleasant. -Chickadee provides no built-in support for live coding, but it's -fairly easy to hook up a special kind of REPL yourself. - -First, create a cooperative REPL server (It's important to use Guile's -cooperative REPL server instead of the standard REPL server in -@code{(system repl server)} to avoid thread synchronization issues). -Then, in the game loop's update procedure, call -@code{poll-coop-repl-server} and pass the REPL object. Here is a -template to follow: - -@example -(use-modules (chickadee) - (system repl coop-server)) - -(define repl (spawn-coop-repl-server)) - -(define (update dt) - (poll-coop-repl-server repl) - ...) - -(run-game #:update update ...) -@end example - -To use the REPL, connect to it via port 37146. Telnet will do the -trick, but using the @uref{https://www.nongnu.org/geiser/, Geiser} -extension for Emacs is by far the best way to develop at the REPL with -Guile. Use @code{M-x connect-to-guile} to connect to the REPL server. - @node Math @section Math @@ -1608,7 +1570,6 @@ blocks to implement additional rendering techniques. * Colors:: Such pretty colors... * Textures:: 2D images, tile atlases, cube maps, etc. * Sprites:: Draw 2D images. -* 9-Patches:: Scalable bitmap boxes. * Fonts:: Drawing text. * Vector Paths:: Draw filled and stroked paths. * Particles:: Pretty little flying pieces! @@ -1617,12 +1578,12 @@ blocks to implement additional rendering techniques. * Lights:: Dynamic 3D lighting. * Skyboxes:: Backgrounds for 3D environments. * Meshes:: 3D meshes and materials. -* Blending:: Control how pixels are combined. +* Buffers:: Send data to the GPU. +* Shaders:: Create custom GPU programs. * Framebuffers:: Render to texture. * Viewports:: Restrict rendering to a particular area. +* Render Settings:: Depth tests, stencil tests, polygon modes, etc. * Rendering Engine:: Rendering state management. -* Buffers:: Send data to the GPU. -* Shaders:: Create custom GPU programs. @end menu @node Colors @@ -1936,6 +1897,46 @@ Return the width of @var{texture} in pixels. Return the height of @var{texture} in pixels. @end deffn +@deffn {Procedure} current-texture-0 +Return the current texture associated with texture unit 0 on the GPU. +@end deffn + +@deffn {Procedure} current-texture-1 +Return the current texture associated with texture unit 1 on the GPU. +@end deffn + +@deffn {Procedure} current-texture-2 +Return the current texture associated with texture unit 2 on the GPU. +@end deffn + +@deffn {Procedure} current-texture-3 +Return the current texture associated with texture unit 3 on the GPU. +@end deffn + +@deffn {Procedure} current-texture-4 +Return the current texture associated with texture unit 4 on the GPU. +@end deffn + +@defvar g:texture-0 +Render state for texture unit 0 (@pxref{Rendering Engine}.) +@end defvar + +@defvar g:texture-1 +Render state for texture unit 1 (@pxref{Rendering Engine}.) +@end defvar + +@defvar g:texture-2 +Render state for texture unit 2 (@pxref{Rendering Engine}.) +@end defvar + +@defvar g:texture-3 +Render state for texture unit 3 (@pxref{Rendering Engine}.) +@end defvar + +@defvar g:texture-4 +Render state for texture unit 4 (@pxref{Rendering Engine}.) +@end defvar + @subsubsection Tile Atlases It is common practice to combine multiple bitmap images into a single @@ -2034,6 +2035,8 @@ The area drawn to is as big as the texture, by default. To draw to an arbitrary section of the screen, specify @var{rect}. @end deffn +@subsubsection Sprite Batches + It's not uncommon to need to draw hundreds or thousands of sprites each frame. However, GPUs (graphics processing units) are tricky beasts that prefer to be sent few, large chunks of data to render @@ -2089,8 +2092,7 @@ Render @var{batch} using @var{blend-mode}. Alpha blending is used by default. @end deffn -@node 9-Patches -@subsection 9-Patches +@subsubsection 9-Patches A 9-patch is a method of rendering a texture so that it can be stretched to cover an area of any size without becoming distorted. @@ -2110,7 +2112,8 @@ the top and bottom sides, which can be stretched or tiled horizontally The most common application of this technique is for graphical user interface widgets like buttons and dialog boxes which are often dynamically resizable. By using a 9-patch, they can be rendered at -any size without scaling artifacts. +any size without scaling artifacts. The @code{(chickadee graphics +9-patch)} module provides this functionality. @deffn {Procedure} draw-9-patch texture rect @ [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] @ @@ -2132,8 +2135,8 @@ To make margins of differing sizes, the @var{top-margin}, @var{bottom-margin}, @var{left-margin}, and @var{right-margin} arguments may be used. -Refer to @code{draw-sprite} (@pxref{Sprites}) for information about -the other arguments as they are the same. +Refer to @code{draw-sprite} for information about the other arguments +as they are the same. @end deffn @node Fonts @@ -2344,12 +2347,12 @@ Apply all the given style settings to @var{painter}. Possible style attributes are: @itemize -@item blend-mode -@item fill-color -@item stroke-color -@item stroke-width -@item stroke-feather -@item stroke-cap +@item @code{blend-mode} +@item @code{fill-color} +@item @code{stroke-color} +@item @code{stroke-width} +@item @code{stroke-feather} +@item @code{stroke-cap} @end itemize @example @@ -2579,8 +2582,8 @@ Return a new particle system that may contain up to @var{capacity} particles. Achieving the desired particle effect involves tweaking the following keyword arguments as needed: -- @var{blend-mode}: Pixel blending mode. Alpha blending is used by default. -(@pxref{Blending} for more about blend modes). +- @var{blend-mode}: Pixel blending mode. Alpha blending is used by +default. (@pxref{Render Settings} for more about blend modes). - @var{start-color}: The tint color of the particle at the beginning of its life. White by default. @@ -2988,20 +2991,23 @@ Emits light of a constant intensity in a direction, like sunlight. Emits a cone of light in a direction, like a flashlight. @end itemize -@deffn {Procedure} make-point-light [#:position (vec3 0 0 0)] [#:color black] +@deffn {Procedure} make-point-light [#:position (vec3 0 0 0)] [#:color black] @ + [#:intensity 1] + Return a new point light located at @var{position} that emits @var{color} light. @end deffn @deffn {Procedure} make-directional-light [#:direction (vec3 0 -1 0)] @ - [#:color black] + [#:color black] [#:intensity 1] Return a new directional light that emits @var{color} light in @var{direction}. @end deffn @deffn {Procedure} make-spot-light [#:position (vec3 0 0 0)] @ - [#:direction (vec3 0 -1 0)] [#:color black] [#:cut-off @math{π/4}] + [#:direction (vec3 0 -1 0)] [#:color black] [#:cut-off @math{π/4}] @ + [#:intensity 1] Return a new spot light located at @var{position} that emits @var{color} light in @var{direction} in a cone that cuts off at @@ -3035,6 +3041,10 @@ Return the type of @var{light}, one of: Return the color of @var{light}. @end deffn +@deffn {Procedure} light-intensity light +Return the intensity of @var{light}. +@end deffn + @deffn {Procedure} light-position light Return the position of @var{light}. The value is irrelevant for directional lights. @@ -3046,8 +3056,8 @@ point lights. @end deffn @deffn {Procedure} light-cut-off light -Return the cut off angle of @var{light}. The value is only relevant -for spot lights. +Return the cosine of the cut off angle of @var{light}. The value is +only relevant for spot lights. @end deffn @deffn {Procedure} set-light-color! light color @@ -3377,308 +3387,6 @@ triangles in the resulting sphere increases exponentially with each increment to @var{quality}. @end deffn -@node Blending -@subsection Blending - -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: - -@defvar blend:alpha -Blend pixels according to the values of their alpha channels. This is -the most commonly used blend mode. -@end defvar - -@defvar blend:replace -Overwrite the output pixel color with the color being drawn. -@end defvar - -@defvar blend:add -Add all pixel color values together. The more colors blended -together, the more white the final color becomes. -@end defvar - -@defvar blend:subtract -Subtract all pixel color values. The more colors blended together, -the more black the final color becomes. -@end defvar - -@defvar blend:multiply -@end defvar - -@defvar blend:darken -@end defvar - -@defvar blend:lighten -@end defvar - -@defvar blend:screen -@end defvar - -Custom blend modes can be created using the @code{make-blend-mode} procedure: - -@deffn {Procedure} make-blend-mode equation source-function destination-function -Return a new custom blend mode that applies @var{source-function} to -the source color, @var{destination-function} to the destination color, -and finally applies @var{equation} to the transformed -source/destination color values. These arguments are @emph{not} -procedures, but symbolic representations of the functions that OpenGL -supports. - -Valid values for @var{equation} are: - -@itemize -@item @code{add} -@item @code{subtract} -@item @code{reverse-subtract} -@item @code{min} -@item @code{max} -@item @code{alpha-min} -@item @code{alpha-max} -@end itemize - -Valid values for @var{source-function} are: - -@itemize -@item @code{zero} -@item @code{one} -@item @code{destination-color} -@item @code{one-minus-destination-color} -@item @code{source-alpha-saturate} -@item @code{source-alpha} -@item @code{one-minus-source-alpha} -@item @code{destination-alpha} -@item @code{one-minus-destination-alpha} -@item @code{constant-color} -@item @code{one-minus-constant-color} -@item @code{constant-alpha} -@item @code{one-minus-constant-alpha} -@end itemize - -Valid values for @var{destination-function} are: - -@itemize -@item @code{zero} -@item @code{one} -@item @code{source-color} -@item @code{one-minus-source-color} -@item @code{source-alpha} -@item @code{one-minus-source-alpha} -@item @code{destination-alpha} -@item @code{one-minus-destination-alpha} -@item @code{constant-color} -@item @code{one-minus-constant-color} -@item @code{constant-alpha} -@item @code{one-minus-constant-alpha} -@end itemize - -@end deffn - -@node Framebuffers -@subsection Framebuffers - -A framebuffer is a chunk of memory that the GPU can render things -onto. By default, the framebuffer that is used for rendering is the -one belonging to the game window, but custom framebuffers can be used -as well. A common use-case for custom framebuffers is applying -post-processing effects: The entire scene is rendered to a -framebuffer, and then the contents of that framebuffer are applied to -a post-processing shader and rendered to the game window. The -post-processing shader could do any number of things: scaling, -antialiasing, motion blur, etc. - -@deffn {Procedure} make-framebuffer width height @ - [#:min-filter @code{linear}] @ - [#:mag-filter @code{linear}] @ - [#:wrap-s @code{repeat}] @ - [#:wrap-t @code{repeat}] - -Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high. - -@var{min-filter} and @var{mag-filter} determine the scaling algorithm -applied to the framebuffer when rendering. By default, linear scaling -is used in both cases. To perform no smoothing at all, use -@code{nearest} for simple nearest neighbor scaling. This is typically -the best choice for pixel art games. -@end deffn - -@deffn {Procedure} framebuffer? obj -Return @code{#t} if @var{obj} is a framebuffer. -@end deffn - -@deffn {Procedure} framebuffer-texture fb -Return the texture backing the framebuffer @var{fb}. -@end deffn - -@deffn {Procedure} framebuffer-viewport fb -Return the default viewport (@pxref{Viewports}) used by the -framebuffer @var{fb}. -@end deffn - -@deffn {Procedure} null-framebuffer -The default framebuffer. -@end deffn - -@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 graphics viewport)} module provides the following -API: - -@deffn {Procedure} make-viewport x y width 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? obj -Return @code{#t} if @var{obj} is a viewport. -@end deffn - -@deffn {Procedure} viewport-x viewport -Return the left edge of @var{viewport}. -@end deffn - -@deffn {Procedure} viewport-y viewport -Return the bottom edge of @var{viewport}. -@end deffn - -@deffn {Procedure} viewport-width viewport -Return the width of @var{viewport}. -@end deffn - -@deffn {Procedure} viewport-height viewport -Return the height of @var{viewport}. -@end deffn - -@deffn {Procedure} viewport-clear-color viewport -Return the clear color for @var{viewport}. -@end deffn - -@deffn {Procedure} viewport-clear-flags 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{Buffers}) and -zero or more keyword arguments that the shader understands. Similar -to how Scheme has @code{apply} for calling procedures, Chickadee -provides @code{shader-apply} for calling shaders. - -Additionally, there is some dynamic state that effects how -@code{shader-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{shader-apply} is called. - -The following procedures and syntax can be found in the -@code{(chickadee graphics)} module. - -@deffn {Syntax} shader-apply shader vertex-array @ - [#:uniform-key uniform-value @dots{}] -@deffnx {Syntax} shader-apply* shader vertex-array count @ - [#:uniform-key uniform-value @dots{}] - -Render @var{vertex-array} using @var{shader} with the uniform values -specified in the following keyword arguments. - -While @code{shader-apply} will draw every vertex in @var{vertex-array}, -@code{shader-apply*} will only draw @var{count} vertices. -@end deffn - -@deffn {Syntax} shader-apply/instanced shader vertex-array @ - n [#:uniform-key uniform-value @dots{}] -@deffnx {Syntax} shader-apply/instanced shader vertex-array @ - count n [#:uniform-key uniform-value @dots{}] - -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{shader-apply/instanced} will draw every vertex in -@var{vertex-array}, @code{shader-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}). -@end deffn - -@deffn {Procedure} current-depth-test -Return @code{#t} if depth testing is currently enabled (@pxref{Blending}). -@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 viewport body @dots{} -Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}). -@end deffn - -@deffn {Syntax} with-framebuffer framebuffer body @dots{} -Evaluate @var{body} with the current framebuffer bound to -@var{framebuffer} (@pxref{Framebuffers}). -@end deffn - -@deffn {Syntax} with-blend-mode blend-mode body @dots{} -Evaluate @var{body} with the current blend mode bound to -@var{blend-mode} (@pxref{Blending}). -@end deffn - -@deffn {Syntax} with-depth-test depth-test? body @dots{} -Evaluate @var{body} with the depth-test disabled if @var{depth-test?} -is @code{#f}, or enabled otherwise (@pxref{Blending}). -@end deffn - -@deffn {Syntax} with-texture texture body @dots{} -Evaluate @var{body} with the current texture bound to @var{texture} -(@pxref{Textures}). -@end deffn - -@deffn {Syntax} with-projection projection body @dots{} -Evaluate @var{body} with the current projection matrix bound to -@var{projection} (@pxref{Matrices}). -@end deffn - @node Buffers @subsection Buffers @@ -3875,6 +3583,14 @@ 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. +@deffn {Procedure} current-buffer +Return the current buffer. +@end deffn + +@defvar g:buffer +Render state for buffers (@pxref{Rendering Engine}.) +@end defvar + This form is useful for streaming buffers that need to update their contents dynamically, such as a sprite batch. @end deffn @@ -4025,6 +3741,14 @@ data for @var{vertex-array}. Return the primitive rendering mode for @var{vertex-array}. @end deffn +@deffn {Procedure} current-vertex-array +Return the current vertex array. +@end deffn + +@defvar g:vertex-array +Render state for vertex arrays (@pxref{Rendering Engine}.) +@end defvar + @node Shaders @subsection Shaders @@ -4181,38 +3905,43 @@ user-defined compound structs, such as this one: @example @verbatim -struct DirectionalLight { - vec3 direction; - vec3 ambient; - vec3 diffuse; - vec3 specular; +struct Light { + bool enabled; + int type; + vec3 position; + vec3 direction; + vec4 color; + float intensity; + float cutOff; }; -uniform DirectionalLight light; +uniform Light light; @end verbatim @end example While @code{light} is declared as a single uniform in the shader code, -OpenGL translates this into @emph{four} uniforms in this case: One -uniform each member of the @code{DirectionalLight} struct. This poses -a problem for sending Scheme data to the GPU. How can compound Scheme -data translate into compound uniform data on the GPU? The answer is -with shader types. Shader types are a special kind of Guile struct -that provide a one-to-one mapping between a Scheme data structure and -a shader struct. +OpenGL translates this into @emph{seven} uniforms in this case: One +uniform each member of the @code{Light} struct. This poses a problem +for sending Scheme data to the GPU. How can compound Scheme data +translate into compound uniform data on the GPU? The answer is with +shader types. Shader types are a special kind of Guile struct that +provide a one-to-one mapping between a Scheme data structure and a +shader struct. Some example code will explain this concept best. Here is the Scheme -equivalent of the @code{DirectionalLight} struct: +equivalent of the @code{Light} struct: @example -(define-shader-type <directional-light> - make-directional-light - directional-light? - (float-vec3 direction directional-light-direction) - (float-vec3 ambient directional-light-ambient) - (float-vec3 diffuse directional-light-diffuse) - (float-vec3 specular directional-light-specular) - (float shininess directional-light-shininess)) +(define-shader-type <light> + make-light + light? + (bool enabled light-enabled?) + (int type light-type) + (float-vec3 position light-position) + (float-vec3 direction light-direction) + (float-vec4 color light-color) + (float intensity light-intensity) + (float cut-off light-cut-off)) @end example The macro @code{define-shader-type} closely resembles the familiar @@ -4255,17 +3984,25 @@ A 3D vector (@pxref{Vectors}.) @end defvar @defvar float-vec4 -A color. +A color (@pxref{Colors}) or rectangle (@pxref{Rectangles}.) +@end defvar + +@defvar mat3 +A 3x3 matrix (@pxref{Matrices}.) @end defvar @defvar mat4 -A matrix (@pxref{Matrices}.) +A 4x4 matrix (@pxref{Matrices}.) @end defvar @defvar sampler-2d A texture (@pxref{Textures}.) @end defvar +@defvar sampler-cube +A cube map (@pxref{Textures}.) +@end defvar + @defvar local-field A special type that means that the data is for the client-side (Scheme-side) only and should not be sent to the GPU. Any object may @@ -4297,6 +4034,573 @@ optional. Return @code{#t} if @var{obj} is a shader data type object. @end deffn +@node Framebuffers +@subsection Framebuffers + +A framebuffer is a chunk of memory that the GPU can render things +onto. By default, the framebuffer that is used for rendering is the +one belonging to the game window, but custom framebuffers can be used +as well. A common use-case for custom framebuffers is applying +post-processing effects: The entire scene is rendered to a +framebuffer, and then the contents of that framebuffer are applied to +a post-processing shader and rendered to the game window. The +post-processing shader could do any number of things: scaling, +antialiasing, motion blur, etc. + +@deffn {Procedure} make-framebuffer width height @ + [#:min-filter @code{linear}] @ + [#:mag-filter @code{linear}] @ + [#:wrap-s @code{repeat}] @ + [#:wrap-t @code{repeat}] + +Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high. + +@var{min-filter} and @var{mag-filter} determine the scaling algorithm +applied to the framebuffer when rendering. By default, linear scaling +is used in both cases. To perform no smoothing at all, use +@code{nearest} for simple nearest neighbor scaling. This is typically +the best choice for pixel art games. +@end deffn + +@deffn {Procedure} framebuffer? obj +Return @code{#t} if @var{obj} is a framebuffer. +@end deffn + +@deffn {Procedure} framebuffer-texture fb +Return the texture backing the framebuffer @var{fb}. +@end deffn + +@deffn {Procedure} framebuffer-viewport fb +Return the default viewport (@pxref{Viewports}) used by the +framebuffer @var{fb}. +@end deffn + +@deffn {Procedure} null-framebuffer +The default framebuffer. +@end deffn + +@deffn {Procedure} current-framebuffer +Return the current framebuffer. +@end deffn + +@defvar g:framebuffer +Render state for framebuffers (@pxref{Rendering Engine}.) +@end defvar + +@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 graphics viewport)} module provides the following +API: + +@deffn {Procedure} make-viewport x y width 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? obj +Return @code{#t} if @var{obj} is a viewport. +@end deffn + +@deffn {Procedure} viewport-x viewport +Return the left edge of @var{viewport}. +@end deffn + +@deffn {Procedure} viewport-y viewport +Return the bottom edge of @var{viewport}. +@end deffn + +@deffn {Procedure} viewport-width viewport +Return the width of @var{viewport}. +@end deffn + +@deffn {Procedure} viewport-height viewport +Return the height of @var{viewport}. +@end deffn + +@deffn {Procedure} viewport-clear-color viewport +Return the clear color for @var{viewport}. +@end deffn + +@deffn {Procedure} viewport-clear-flags viewport +Return the list of clear flags for @var{viewport}. +@end deffn + +@deffn {Procedure} current-viewport +Return the current viewport. +@end deffn + +@defvar g:viewport +Render state for viewports (@pxref{Rendering Engine}.) +@end defvar + +@node Render Settings +@subsection Render Settings + +@subsubsection Blending + +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. The +@code{(chickadee graphics blend)} module provides a data type for +blending modes. + +Chickadee provides the following blend modes: + +@defvar blend:alpha +Blend pixels according to the values of their alpha channels. This is +the most commonly used blend mode. +@end defvar + +@defvar blend:replace +Overwrite the output pixel color with the color being drawn. +@end defvar + +@defvar blend:add +Add all pixel color values together. The more colors blended +together, the more white the final color becomes. +@end defvar + +@defvar blend:subtract +Subtract all pixel color values. The more colors blended together, +the more black the final color becomes. +@end defvar + +@defvar blend:multiply +@end defvar + +@defvar blend:darken +@end defvar + +@defvar blend:lighten +@end defvar + +@defvar blend:screen +@end defvar + +Custom blend modes can be created using the @code{make-blend-mode} procedure: + +@deffn {Procedure} make-blend-mode equation source-function destination-function +Return a new custom blend mode that applies @var{source-function} to +the source color, @var{destination-function} to the destination color, +and finally applies @var{equation} to the transformed +source/destination color values. These arguments are @emph{not} +procedures, but symbolic representations of the functions that OpenGL +supports. + +Valid values for @var{equation} are: + +@itemize +@item @code{add} +@item @code{subtract} +@item @code{reverse-subtract} +@item @code{min} +@item @code{max} +@item @code{alpha-min} +@item @code{alpha-max} +@end itemize + +Valid values for @var{source-function} are: + +@itemize +@item @code{zero} +@item @code{one} +@item @code{destination-color} +@item @code{one-minus-destination-color} +@item @code{source-alpha-saturate} +@item @code{source-alpha} +@item @code{one-minus-source-alpha} +@item @code{destination-alpha} +@item @code{one-minus-destination-alpha} +@item @code{constant-color} +@item @code{one-minus-constant-color} +@item @code{constant-alpha} +@item @code{one-minus-constant-alpha} +@end itemize + +Valid values for @var{destination-function} are: + +@itemize +@item @code{zero} +@item @code{one} +@item @code{source-color} +@item @code{one-minus-source-color} +@item @code{source-alpha} +@item @code{one-minus-source-alpha} +@item @code{destination-alpha} +@item @code{one-minus-destination-alpha} +@item @code{constant-color} +@item @code{one-minus-constant-color} +@item @code{constant-alpha} +@item @code{one-minus-constant-alpha} +@end itemize + +@end deffn + +@subsubsection Polygon Modes and Culling + +The @code{(chickadee graphics polygon)} module provides access to the +@code{g:polygon-mode} and @code{g:cull-face-mode} render states. + +@defvar fill-polygon-mode +Completely fill in the polygon. This is the default mode. +@end defvar + +@defvar line-polygon-mode +Render only the edges of the polygon. Produces a wireframe. +@end defvar + +@defvar point-polygon-mode +Render only the vertex positions as points. +@end defvar + +@deffn {Procedure} make-polygon-mode front back +Return a new polygon mode that uses the method @var{front} for the +front face and @var{back} for the back face. The valid modes are +@code{fill}, @code{line}, and @var{point}. +@end deffn + +@deffn {Procedure} polygon-mode? obj +Return @code{#t} if @var{obj} is a polygon mode. +@end deffn + +@deffn {Procedure} current-polygon-mode +Return the current polygon mode. +@end deffn + +@defvar g:polygon-mode +Render state for polygon modes (@pxref{Rendering Engine}.) +@end defvar + +@defvar no-cull-face-mode +Don't cull any faces. +@end defvar + +@defvar back-cull-face-mode +Cull only back faces. +@end defvar + +@defvar front-cull-face-mode +Cull only front faces. +@end defvar + +@defvar front-and-back-cull-face-mode +Cull both front and back faces. +@end defvar + +@deffn {Procedure} cull-face-mode? obj +Return @code{#t} if @var{obj} is a cull face mode. +@end deffn + +@deffn {Procedure} cull-face-mode-front? cull-face-mode +Return @code{#t} if @var{cull-face-mode} culls front faces. +@end deffn + +@deffn {Procedure} cull-face-mode-back? cull-face-mode +Return @code{#t} if @var{cull-face-mode} culls back faces. +@end deffn + +@deffn {Procedure} current-cull-face-mode +Return the current cull face mode. +@end deffn + +@defvar g:cull-face-mode +Render state for cull face modes (@pxref{Rendering Engine}.) +@end defvar + +@subsubsection Depth Testing + +The @code{(chickadee graphics depth)} module provides access to the +@code{g:depth-test} render state. + +@deffn {Procedure} make-depth-test [#:write? #t] [#:function 'less-than] @ + [#:near 0.0] [#:far 1.0] + +Return a new depth test object. If @var{write} is @code{#t}, the +depth buffer will be written to during a draw call. @var{near} and +@var{far} define the min/max Z values for which depth testing may +pass. + +@var{function} specifies how the depth value of pixel being drawn +compares to the depth value that is already in the depth buffer. When +this comparison is true, the depth test passes and the pixel is drawn. +When it fails, the pixel is discarded. + +The possible values of @var{function} are: + +@itemize +@item @code{always} +@item @code{never} +@item @code{equal} +@item @code{not-equal} +@item @code{less-than} +@item @code{less-than-or-equal} +@item @code{greater-than} +@item @code{greater-than-or-equal} +@end itemize + +@end deffn + +@deffn {Procedure} depth-test? obj +Return @code{#t} when @var{obj} is a depth test object. +@end deffn + +@deffn {Procedure} depth-test-write? depth-test +Return @code{#t} when @var{depth-test} will write to the depth buffer. +@end deffn + +@deffn {Procedure} depth-test-function depth-test +Return the comparison function of @var{depth-test}. +@end deffn + +@deffn {Procedure} depth-test-near depth-test +Return the near Z value of @var{depth-test}. +@end deffn + +@deffn {Procedure} depth-test-far depth-test +Return the far Z value of @var{depth-test}. +@end deffn + +@deffn {Procedure} current-depth-test +Return the current depth test. +@end deffn + +@defvar g:depth-test +Render state for depth tests (@pxref{Rendering Engine}.) +@end defvar + +@subsubsection Stencil Testing + +The @code{(chickadee graphics stencil)} module provides access to the +@code{g:stencil-test} render state. + +@defvar default-stencil-test +A stencil test that always passes. +@end defvar + +@deffn {Procedure} make-stencil-test [#:mask #xFF] [#:function always] @ + [#:function-mask #xFF] [#:reference 0] [#:on-fail keep] @ + [#:on-depth-fail keep] [#:on-pass keep] [#:mask-front mask] @ + [#:mask-back mask] [#:function-mask-front function-mask] @ + [#:function-mask-back function-mask] [#:refrence-front reference] @ + [#:reference-back reference] [#:on-fail-front on-fail] @ + [#:on-fail-back on-fail] [#:on-depth-fail-front on-depth-fail] @ + [#:on-depth-fail-back on-depth-fail] [#:on-pass-front on-pass] @ + [#:on-pass-back on-pass] + +Return a new stencil test object. Different configurations can be +used for the front and back faces by using the arguments that end in +``front'' or ``back''. + +Valid values for @var{on-pass}, @var{on-fail}, and @var{on-depth-fail} +are: + +@itemize +@item @code{zero} +@item @code{keep} +@item @code{replace} +@item @code{increment} +@item @code{increment-wrap} +@item @code{decrement} +@item @code{decrement-wrap} +@item @code{invert} +@end itemize + +Valid values for @var{function} are: + +@itemize +@item @code{always} +@item @code{never} +@item @code{equal} +@item @code{not-equal} +@item @code{less-than} +@item @code{less-than-or-equal} +@item @code{greater-than} +@item @code{greater-than-or-equal} +@end itemize + +@end deffn + +@deffn {Procedure} stencil-test? obj +Return @code{#t} when @var{obj} is a stencil test object. +@end deffn + +@deffn {Procedure} stencil-test-mask-front stencil-test +Return the front mask of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-mask-back stencil-test +Return the back mask of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-function-front stencil-test +Return the front function of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-function-back stencil-test +Return the back function of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-function-mask-front stencil-test +Return the front function-mask of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-function-mask-back stencil-test +Return the back function-mask of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-reference-front stencil-test +Return the front reference value of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-reference-back stencil-test +Return the back reference value of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-fail-front stencil-test +Return the front failure action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-fail-back stencil-test +Return the back failure action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-depth-fail-front stencil-test +Return the front depth test failure action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-depth-fail-back stencil-test +Return the back depth test failure action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-pass-front stencil-test +Return the front pass action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} stencil-test-on-pass-back stencil-test +Return the back pass action of @var{stencil-test}. +@end deffn + +@deffn {Procedure} current-stencil-test +Return the current stencil test. +@end deffn + +@defvar g:stencil-test +Render state for stencil testing (@pxref{Rendering Engine}.) +@end defvar + +@subsubsection Multisample Antialiasing + +Multisample antialiasing is a feature supported by many, but not all, +graphics cards. It is a nice easy way to improve the final frame that +the user sees, particularly in 3D scenes. The @code{(chickadee +graphics multisample)} module provides access to the +@code{g:multisample?} render state. + +@deffn {Procedure} current-multisample +Return @code{#t} if multisampling is enabled. +@end deffn + +@defvar g:multisample? +Render state for multisampling (@pxref{Rendering Engine}.) +@end defvar + +@node Rendering Engine +@subsection Rendering Engine + +The @code{(chickadee graphics engine)} module provides a Scheme +abstraction to the state of the GPU driver. When the Chickadee game +loop launches, it takes care to initialize the engine. All draw calls +and state changes happen within the context of this engine. + +Performing a custom draw call could look something like this: + +@example +(with-graphics-state ((g:blend-mode blend:alpha) + (g:texture-0 my-texture)) + (shader-apply my-shader #:foo 1)) +@end example + +@subsubsection Render States + +Render states represent individual state values on the GPU. For +example, the current shader. As a naming convention, Chickadee +prefixes variables containing render states with @code{g:}. Render +states can be manipulated using the @code{with-graphics-state} macro. + +@deffn {Syntax} with-graphics-state ((name value) @dots{}) body @dots{} +Evaluate @var{body} with render states defined by @var{name} changed +to @var{value}. The render states are restored to their previous +values afterwards. +@end deffn + +One additional piece of state that the rendering engine has, that is +not part of the GPU state, is the current projection matrix: + +@deffn {Procedure} current-projection +Return the currently bound projection matrix (@pxref{Matrices}). +@end deffn + +@deffn {Syntax} with-projection projection body @dots{} +Evaluate @var{body} with the current projection matrix bound to +@var{projection} (@pxref{Matrices}). +@end deffn + +@subsubsection Rendering + +Chickadee likens a GPU draw call to a Scheme procedure call. A shader +(@pxref{Shaders}) is like a procedure for the GPU to apply. Shaders +are passed arguments: The positional arguments are vertex array +attributes (@pxref{Buffers}) and the keyword arguments correspond to +the shader's uniform variables. Scheme uses @code{apply} to call a +procedure, so Chickadee uses @code{shader-apply} to call a shader. + +@deffn {Syntax} shader-apply shader vertex-array @ + [#:uniform-key uniform-value @dots{}] +@deffnx {Syntax} shader-apply* shader vertex-array count @ + [#:uniform-key uniform-value @dots{}] + +Render @var{vertex-array} using @var{shader} with the uniform values +specified in the following keyword arguments. + +While @code{shader-apply} will draw every vertex in @var{vertex-array}, +@code{shader-apply*} will only draw @var{count} vertices. +@end deffn + +@deffn {Syntax} shader-apply/instanced shader vertex-array @ + n [#:uniform-key uniform-value @dots{}] +@deffnx {Syntax} shader-apply/instanced shader vertex-array @ + count n [#:uniform-key uniform-value @dots{}] + +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{shader-apply/instanced} will draw every vertex in +@var{vertex-array}, @code{shader-apply*} will only draw @var{count} +vertices. +@end deffn + @node Audio @section Audio @@ -4317,15 +4621,9 @@ in the load hook (or anywhere else once the game loop is running) and play it! @example -(use-modules (chickadee audio)) - -(define audio #f) - -(define (load) - (set! audio (load-audio "neat-sound-effect.wav")) - (audio-play audio)) +(define sample (load-audio "neat-sound-effect.wav")) -(run-game #:load load) +(audio-play sample) @end example For more advanced usage, check out the full API reference in the diff --git a/doc/chickadee.texi b/doc/chickadee.texi index a65af9e..0585688 100644 --- a/doc/chickadee.texi +++ b/doc/chickadee.texi @@ -4,7 +4,7 @@ @settitle The Chickadee Game Toolkit @c %**end of header @copying -Copyright @copyright{} 2017-2020 David Thompson @email{davet@@gnu.org} +Copyright @copyright{} 2017-2021 David Thompson @email{davet@@gnu.org} @quotation Permission is granted to copy, distribute and/or modify this document @@ -53,8 +53,8 @@ The document was typeset with * Installation:: Installing Chickadee. * Getting Started:: Writing your first Chickadee program. * Command Line Interface:: Run Chickadee programs from the terminal. +* Live Coding:: Tips for building games from the REPL. * API Reference:: Chickadee API reference. - * Copying This Manual:: The GNU Free Documentation License and you! * Index:: @end menu @@ -93,7 +93,6 @@ Chickadee depends on the following packages: @item libvorbisfile @end itemize - @node Getting Started @chapter Getting Started @@ -271,11 +270,57 @@ after each change. @item --repl-server[=@var{port}] Launch a REPL server on port @var{port}, or 37146 by default. -Especially useful when paired with the -@url{https://www.nongnu.org/geiser/, Geiser} extension for Emacs. + +@command{telnet localhost 37146} (or whatever port number was given) +will do the trick, but using the @uref{https://www.nongnu.org/geiser/, +Geiser} extension for Emacs is by far the best way to develop at the +REPL with Guile. Use @code{M-x connect-to-guile} to connect to the +REPL server. @end table +@node Live Coding +@chapter Live Coding + +One of the biggest appeals of any Lisp dialect is the ability to use +the ``read-eval-print loop'' (REPL for short) to build programs +iteratively and interactively while the program is running. However, +programs that run in an event loop and respond to user input (such as +a game using the Chickadee library!) require special care for this +workflow to be pleasant. + +If you are using the @command{chickadee play} command to run your +game, then the @code{--repl} or @code{--repl-server} arguments are all +you need to get a live coding environment running. + +If, however, you are using @code{run-game} to start the game loop then +it's still fairly easy to hook up a special kind of REPL by yourself. + +First, create a cooperative REPL server (It's important to use Guile's +cooperative REPL server instead of the standard REPL server in +@code{(system repl server)} to avoid thread synchronization issues). +Then, in the game loop's update procedure, call +@code{poll-coop-repl-server} and pass the REPL object. Here is a +template to follow: + +@example +(use-modules (chickadee) + (system repl coop-server)) + +(define repl (spawn-coop-repl-server)) + +(define (update dt) + (poll-coop-repl-server repl) + ...) + +(run-game #:update update ...) +@end example + +To use the REPL, connect to it via port 37146. Telnet will do the +trick, but using the @uref{https://www.nongnu.org/geiser/, Geiser} +extension for Emacs is by far the best way to develop at the REPL with +Guile. Use @code{M-x connect-to-guile} to connect to the REPL server. + @node API Reference @chapter API Reference |