2 * Kernel:: The fundamental components.
3 * Math:: Linear algebra, spatial partitioning, and more.
4 * Graphics:: Eye candy.
5 * Scripting:: Bringing the game world to life.
11 At the very core of Chickadee, in the @code{(chickadee game-loop)}
12 module, lies an event loop. This loop, or ``kernel'', is responsible
13 for ensuring that the game is updated at the desired interval,
14 rendering the current state of the game world, and handling errors if
15 they occur. The kernel implements what is known as a ``fixed
16 timestep'' game loop, meaning that the game simulation will be
17 advanced by a fixed interval of time and will never vary from frame to
18 frame, unlike some other styles of game loops. The appropriately
19 named @code{run-game*} and @code{abort-game} procedures are the entry
20 and exit points to the Chickadee game loop kernel.
22 On its own, the kernel does not do very much at all. In order to
23 actually respond to input events, update game state, or render output,
24 the programmer must provide an engine. But don’t worry, you don’t
25 have to start from scratch! Chickadee comes with a simple engine that
26 uses SDL to create a graphical window and handle input devices, and
27 OpenGL to handle rendering. This default engine is enough for most
28 users to get started writing games quickly. More advanced users may
29 want to write a custom engine that uses a different I/O system.
30 Perhaps you are writing a text adventure or roguelike that reads from
31 and writes to a terminal instead of a graphical window. The game loop
32 kernel makes no assumptions.
34 @deffn {Procedure} run-game [#:update] [#:render] [#:time] [#:error] @
37 Start the game loop. This procedure will not return until
38 @code{abort-game} is called.
40 The core game loop is generic and requires four additional procedures
45 @var{update}: Called @var{update-hz} times per second to advance the
46 game simulation. This procedure is called with a single argument: The
47 amount of time that has passed since the last update, in milliseconds.
49 @var{render}: Called each iteration of the loop to render the game to
50 the desired output device. This procedure is called with a single
51 argument: A value in the range [0, 1] which represents how much time
52 has past since the last game state update relative to the upcoming
53 game state update, as a percentage. Because the game state is updated
54 independent of rendering, it is often the case that rendering is
55 occuring between two updates. If the game is rendered as it was
56 during the last update, a strange side-effect will occur that makes
57 animation appear rough or ``choppy''. To counter this, the
58 @var{alpha} value can be used to perfrom a linear interpolation of a
59 moving object between its current position and its previous position.
60 This odd trick has the pleasing result of making the animation look
61 smooth again, but requires keeping track of previous state.
63 @var{time}: Called to get the current time in milliseconds. This
64 procedure is called with no arguments.
66 @var{error}: Called when an error from the @var{update} or
67 @var{render} procedures reaches the game loop. This procedure is
68 called with three arguments: The call stack, the error key, and the
69 error arguments. If no error handler is provided, the default
70 behavior is to simply re-throw the error.
75 @deffn {Procedure} abort-game
76 Stop the currently running Chickadee game loop.
79 Since most users will want to write 2D/3D games with hardware
80 accelerated graphics rendering, controlled via keyboard, mouse, or
81 game controller, Chickadee comes with an easy to use engine just for
82 this purpose in the @code{(chickadee)} module: @code{run-game}.
84 @deffn {Procedure} run-game [#:window-title "Chickadee!"] @
85 [#:window-width 640] [#:window-height 480] @
86 [#:window-fullscreen? @code{#f}] [#:update-hz 60] @
87 [#:load] [#:update] [#:draw] [#:quit] @
88 [#:key-press] [#:key-release] [#:text-input] @
89 [#:mouse-press] [#:mouse-release] [#:mouse-move] @
90 [#:controller-add] [#:controller-remove] [#:controller-press] @
91 [#:controller-release] [#:controller-move] [#:error]
93 Run the Chickadee game loop using the SDL engine in OpenGL mode.
95 A new graphical window will be opened with @var{window-width} x
96 @var{window-height} as its dimensions, @var{window-title} as its
97 title, and in fullscreen mode if @var{window-fullscreen?} is
102 @var{load}: Called with zero arguments when the game window has opened
103 but before the game loop has started. Can be used to perform
104 initialization that requires an open window and OpenGL context such as
108 @var{update}: Called @var{update-hz} times per second with one
109 argument: The amount of time to advance the game simulation.
112 @var{draw}: Called each time a frame should be rendered with a single
113 argument known as the @code{alpha} value. See the documentation for
114 @code{run-game} for an explanation of this value.
117 @var{quit}: Called with zero arguments when the user tries to close
118 the game window. The default behavior is to exit the game.
121 @var{key-press}: Called with four arguments when a key is pressed on
126 @var{key}: The symbolic name of the ``virtual'' key that was pressed.
127 For example: @code{backspace}. It's called a virtual key because the
128 operating system may map a physical keyboard key to another key
129 entirely, such as how the author likes to bind the ``caps lock'' key
133 @var{scancode}: The symbolic name of the physical key that was
137 @var{modifiers}: A list of the symbolic names of modifier keys that
138 were being held down when the key was pressed. Possible values
139 include @code{ctrl}, @code{alt}, and @code{shift}.
142 @var{repeat?}: @code{#t} if this is a repeated press of the same key.
147 @var{key-release}: Called with three arguments when a key is released
152 @var{key}: The symbolic name of the ``virtual'' key that was released.
155 @var{scancode}: The symbolic name of the physical key that was
159 @var{modifiers}: A list of the symbolic names of modifier keys that
160 were being held down when the key was released.
165 @var{text-input}: Called with a single argument, a string of text,
166 when printable text is typed on the keyboard.
169 @var{mouse-press}: Called with four arguments when a mouse button is
174 @var{button}: The symbolic name of the button that was pressed, such
175 as @code{left}, @code{middle}, or @code{right}.
178 @var{clicks}: The number of times the button has been clicked in a row.
181 @var{x}: The x coordinate of the mouse cursor.
184 @var{y}: The y coordinate of the mouse cursor.
189 @var{mouse-release}: Called with three arguments when a mouse button
195 @var{button}: The symbolic name of the button that was released.
198 @var{x}: The x coordinate of the mouse cursor.
201 @var{y}: The y coordinate of the mouse cursor.
206 @var{mouse-move}: Called with five arguments when the mouse is moved:
211 @var{x}: The x coordinate of the mouse cursor.
214 @var{y}: The y coordinate of the mouse cursor.
217 @var{dx}: The amount the mouse has moved along the x axis since the
218 last mouse move event.
221 @var{dy}: The amount the mouse has moved along the y axis since the
222 last mouse move event.
225 @var{buttons}: A list of the buttons that were pressed down when the
231 @var{controller-add}: Called with a single argument, an SDL game
232 controller object, when a game controller is connected.
235 @var{controller-remove}: Called with a single argument, an SDL game
236 controller object, when a game controller is disconnected.
239 @var{controller-press}: Called with two arguments when a button on a
240 game controller is pressed:
245 @var{controller}: The controller that triggered the event.
248 @var{button}: The symbolic name of the button that was pressed.
249 Possible buttons are:
273 @code{right-shoulder}
288 @var{controller-release}: Called with two arguments when a button on a
289 game controller is released:
294 @var{controller}: The controller that triggered the event.
297 @var{button}: The symbolic name of the button that was released.
302 @var{controller-move}: Called with three arguments when an analog
303 stick or trigger on a game controller is moved:
308 @var{controller}: The controller that triggered the event.
311 @var{axis}: The symbolic name of the axis that was moved. Possible
332 @var{error}: Called with three arguments when an error occurs:
337 @var{stack}: The call stack at the point of error.
340 @var{key}: The exception key.
343 @var{args}: The arguments thrown with the exception.
347 The default behavior is to re-throw the error.
356 Chickadee contains data types and procedures for performing the most
357 common computations in video game simulations such as linear algebra
358 with vectors and matrices and axis-aligned bounding box collision
362 * Basics:: Commonly used, miscellaneous things.
363 * Vectors:: Euclidean vectors.
364 * Rectangles:: Axis-aligned bounding boxes.
365 * Grid:: Spatial partitioning for bounding boxes.
366 * Matrices:: Transformation matrices.
367 * Quaternions:: Rotations about an arbitrary axis.
368 * Easings:: Easing functions for interesting animations.
369 * Bezier Curves:: Cubic Bezier curves and paths in 2D space.
370 * Path Finding:: Generic A* path finding.
377 An essential constant for all trigonometry. @code{@U{03C0}} is the ratio
378 of a circle's circumferences to its diameter. Since @code{@U{03C0}} is an
379 irrational number, the @var{pi} in Chickadee is a mere floating point
380 approximation that is ``good enough.''
387 @deffn {Procedure} cotan @var{z}
388 Return the cotangent of @var{z}.
394 Unlike Scheme's vector data type, which is a sequence of arbitrary
395 Scheme objects, Chickadee's @code{(chickadee math vector)} module
396 provides vectors in the linear algebra sense: Sequences of numbers
397 specialized for particular coordinate spaces. As of now, Chickadee
398 provides 2D and 3D vectors, with 4D vector support coming in a future
401 Here's a quick example of adding two vectors:
404 (define v (vec2+ (vec2 1 2) (vec2 3 4)))
407 Since vectors are used so frequently, the reader macro @code{#v} is
408 used to cut down on typing:
411 (define v (vec2+ #v(1 2) #v(3 4)))
414 @subsubsection A Note About Performance
416 A lot of time has been spent making Chickadee's vector operations
417 perform relatively efficiently in critical code paths where excessive
418 garbage generation will cause major performance issues. The general
419 rule is that procedures ending with @code{!} perform an in-place
420 modification of one of the arguments in order to avoid allocating a
421 new vector. These procedures are also inlined by Guile's compiler in
422 order to take advantage of optimizations relating to floating point
423 math operations. The downside is that since these are not pure
424 functions, they do not compose well and create more verbose code.
426 @subsubsection 2D Vectors
428 @deffn {Procedure} vec2 @var{x} @var{y}
429 Return a new 2D vector with coordinates (@var{x}, @var{y}).
432 @deffn {Procedure} vec2/polar @var{r} @var{theta}
433 Return a new 2D vector containing the Cartesian representation of the
434 polar coordinate (@var{r}, @var{theta}). The angle @var{theta} is
438 @deffn {Procedure} vec2? @var{obj}
439 Return @code{#t} if @var{obj} is a 2D vector.
442 @deffn {Procedure} vec2-x @var{v}
443 Return the X coordinate of the 2D vector @var{v}.
446 @deffn {Procedure} vec2-y @var{v}
447 Return the Y coordinate of the 2D vector @var{v}.
450 @deffn {Procedure} vec2-copy @var{v}
451 Return a fresh copy of the 2D vector @var{v}.
454 @deffn {Procedure} vec2-magnitude @var{v}
455 Return the magnitude of the 2D vector @var{v}.
458 @deffn {Procedure} vec2-dot-product @var{v1} @var{v2}
459 Return the dot product of the 2D vectors @var{v1} and @var{v2}.
462 @deffn {Procedure} vec2-normalize @var{v}
463 Return the normalized form of the 2D vector @var{v}.
466 @deffn {Procedure} vec2+ @var{v} @var{x}
467 Add @var{x}, either a 2D vector or a scalar (i.e. a real number), to
468 the 2D vector @var{v} and return a new vector containing the sum.
471 @deffn {Procedure} vec2- @var{v} @var{x}
472 Subtract @var{x}, either a 2D vector or a scalar, from the 2D vector
473 @var{v} and return a new vector containing the difference.
476 @deffn {Procedure} vec2* @var{v} @var{x}
477 Multiply the 2D vector @var{v} by @var{x}, a 2D vector or a scalar,
478 and return a new vector containing the product.
481 @deffn {Procedure} set-vec2-x! @var{v} @var{x}
482 Set the X coordinate of the 2D vector @var{v} to @var{x}.
485 @deffn {Procedure} set-vec2-y! @var{v} @var{y}
486 Set the Y coordinate of the 2D vector @var{v} to @var{y}.
489 @deffn {Procedure} set-vec2! @var{v} @var{x} @var{y}
490 Set the X and Y coordinates of the 2D vector @var{v} to @var{x} and
491 @var{y}, respectively.
494 @deffn {Procedure} vec2-copy! @var{source} @var{target}
495 Copy the 2D vector @var{source} into the 2D vector @var{target}.
498 @deffn {Procedure} vec2-add! @var{v} @var{x}
499 Perform an in-place modification of the 2D vector @var{v} by adding
500 @var{x}, a 2D vector or a scalar.
503 @deffn {Procedure} vec2-sub! @var{v} @var{x}
504 Perform an in-place modification of the 2D vector @var{v} by
505 subtracting @var{x}, a 2D vector or a scalar.
508 @deffn {Procedure} vec2-mult! @var{v} @var{x}
509 Perform an in-place modification of the 2D vector @var{v} by
510 multiplying it by @var{x}, a 2D vector or a scalar.
513 @subsubsection 3D Vectors
515 @deffn {Procedure} vec3 @var{x} @var{y}
516 Return a new 2D vector with coordinates (@var{x}, @var{y}).
519 @deffn {Procedure} vec3? @var{obj}
520 Return @code{#t} if @var{obj} is a 3D vector.
523 @deffn {Procedure} vec3-x @var{v}
524 Return the X coordinate of the 3D vector @var{v}.
527 @deffn {Procedure} vec3-y @var{v}
528 Return the Y coordinate of the 3D vector @var{v}.
531 @deffn {Procedure} vec3-z @var{v}
532 Return the Z coordinate of the 3D vector @var{v}.
535 @deffn {Procedure} vec3-copy @var{v}
536 Return a fresh copy of the 3D vector @var{v}.
539 @deffn {Procedure} vec3-magnitude @var{v}
540 Return the magnitude of the 3D vector @var{v}.
543 @deffn {Procedure} vec3-dot-product @var{v1} @var{v2}
544 Return the dot product of the 3D vectors @var{v1} and @var{v2}.
547 @deffn {Procedure} vec3-normalize @var{v}
548 Return the normalized form of the 3D vector @var{v}.
551 @deffn {Procedure} vec3+ @var{v} @var{x}
552 Add @var{x}, either a 3D vector or a scalar (i.e. a real number), to
553 the 3D vector @var{v} and return a new vector containing the sum.
556 @deffn {Procedure} vec3- @var{v} @var{x}
557 Subtract @var{x}, either a 3D vector or a scalar, from the 3D vector
558 @var{v} and return a new vector containing the difference.
561 @deffn {Procedure} vec3* @var{v} @var{x}
562 Multiply the 3D vector @var{v} by @var{x}, a 3D vector or a scalar,
563 and return a new vector containing the product.
566 @deffn {Procedure} set-vec3-x! @var{v} @var{x}
567 Set the X coordinate of the 3D vector @var{v} to @var{x}.
570 @deffn {Procedure} set-vec3-y! @var{v} @var{y}
571 Set the Y coordinate of the 3D vector @var{v} to @var{y}.
574 @deffn {Procedure} set-vec3-z! @var{v} @var{z}
575 Set the Z coordinate of the 3D vector @var{v} to @var{z}.
578 @deffn {Procedure} set-vec3! @var{v} @var{x} @var{y} @var{z}
579 Set the X, Y, and Z coordinates of the 3D vector @var{v} to @var{x},
580 @var{y}, and @var{z}, respectively.
583 @deffn {Procedure} vec3-copy! @var{source} @var{target}
584 Copy the 3D vector @var{source} into the 3D vector @var{target}.
587 @deffn {Procedure} vec3-add! @var{v} @var{x}
588 Perform an in-place modification of the 3D vector @var{v} by adding
589 @var{x}, a 3D vector or a scalar.
592 @deffn {Procedure} vec3-sub! @var{v} @var{x}
593 Perform an in-place modification of the 3D vector @var{v} by
594 subtracting @var{x}, a 3D vector or a scalar.
597 @deffn {Procedure} vec3-mult! @var{v} @var{x}
598 Perform an in-place modification of the 3D vector @var{v} by
599 multiplying it by @var{x}, a 3D vector or a scalar.
603 @subsection Rectangles
605 The @code{(chickadee math rect)} module provides an API for
606 manipulating axis-aligned bounding boxes (AABBs). AABBs are often
607 used for collision detection in games. Common use-cases are defining
608 ``hitboxes'' in platformers or using them for the ``broad phase'' of a
609 collision detection algorithm that uses a more complex (and thus
610 slower) method of determining the actual collisions.
612 Like some of the other math modules, there exists a collection of
613 functions that do in-place modification of rectangles for use in
614 performance critical code paths.
616 @deffn {Procedure} rect @var{x} @var{y} @var{width} @var{height}
617 @deffnx {Procedure} make-rect @var{x} @var{y} @var{width} @var{height}
618 Create a new rectangle that is @var{width} by @var{height} in size and
619 whose bottom-left corner is located at (@var{x}, @var{y}).
622 @deffn {Procedure} rect? @var{obj}
623 Return @code{#t} if @var{obj} is a rectangle.
626 @deffn {Procedure} rect-within? @var{rect1} @var{rect2}
627 Return @code{#t} if @var{rect2} is completely within @var{rect1}.
630 @deffn {Procedure} rect-intersects? @var{rect1} @var{rect2}
631 Return @code{#t} if @var{rect2} overlaps @var{rect1}.
634 @deffn {Procedure} rect-contains? @var{rect} @var{x} @var{y}
635 Return @code{#t} if the coordinates (@var{x}, @var{y}) are within
639 @deffn {Procedure} rect-contains-vec2? @var{rect} @var{v}
640 Return @code{#t} if the 2D vector @var{v} is within the bounds of
644 @deffn {Procedure} rect-x @var{rect}
645 Return the X coordinate of the lower-left corner of @var{rect}.
648 @deffn {Procedure} rect-y @var{rect}
649 Return the Y coordinate of the lower-left corner of @var{rect}.
652 @deffn {Procedure} rect-left @var{rect}
653 Return the left-most X coordinate of @var{rect}.
656 @deffn {Procedure} rect-right @var{rect}
657 Return the right-most X coordinate of @var{rect}.
660 @deffn {Procedure} rect-bottom @var{rect}
661 Return the bottom-most Y coordinate of @var{rect}.
664 @deffn {Procedure} rect-top @var{rect}
665 Return the top-most Y coordinate of @var{rect}.
668 @deffn {Procedure} rect-center-x @var{rect}
669 Return the X coordinate of the center of @var{rect}.
672 @deffn {Procedure} rect-center-y @var{rect}
673 Return the Y coordinate of the center of @var{rect}.
676 @deffn {Procedure} rect-width @var{rect}
677 Return the width of @var{rect}.
680 @deffn {Procedure} rect-height @var{rect}
681 Return the height of @var{rect}.
684 @deffn {Procedure} rect-area @var{rect}
685 Return the surface area covered by @var{rect}.
688 @deffn {Procedure} rect-clamp-x @var{rect} @var{x}
689 Restrict @var{x} to the portion of the X axis covered by @var{rect}.
692 @deffn {Procedure} rect-clamp-y @var{rect} @var{y}
693 Restrict @var{y} to the portion of the Y axis covered by @var{rect}.
696 @deffn {Procedure} rect-clamp @var{rect1} @var{rect2}
697 Return a new rect that adjusts the location of @var{rect1} so that it
698 is completely within @var{rect2}. An exception is thrown in the case
699 that @var{rect1} cannot fit completely within @var{rect2}.
702 @deffn {Procedure} rect-move @var{rect} @var{x} @var{y}
703 Return a new rectangle based on @var{rect} but moved to the
704 coordinates (@var{x}, @var{y}).
707 @deffn {Procedure} rect-move-vec2 @var{rect} @var{v}
708 Return a new rectangle based on @var{rect} but moved to the
709 coordinates in the 2D vector @var{v}.
712 @deffn {Procedure} rect-move-by @var{rect} @var{x} @var{y}
713 Return a new rectangle based on @var{rect} but moved by (@var{x},
714 @var{y}) units relative to its current location.
717 @deffn {Procedure} rect-move-by-vec2 @var{rect} @var{v}
718 Return a new rectangle based on @var{rect} but moved by the 2D vector
719 @var{v} relative to its current location.
722 @deffn {Procedure} rect-inflate @var{rect} @var{width} @var{height}
723 Return a new rectangle based on @var{rect}, but expanded by
724 @var{width} units on the X axis and @var{height} units on the Y axis,
725 while keeping the rectangle centered on the same point.
728 @deffn {Procedure} rect-union @var{rect1} @var{rect2}
729 Return a new rectangle that completely covers the area of @var{rect1}
733 @deffn {Procedure} rect-clip @var{rect1} @var{rect2}
734 Return a new rectangle that is the overlapping region of @var{rect1}
735 and @var{rect2}. If the two rectangles do not overlap, a rectangle of
736 0 width and 0 height is returned.
739 @deffn {Procedure} set-rect-x! @var{rect} @var{x}
740 Set the left X coordinate of @var{rect} to @var{x}.
743 @deffn {Procedure} set-rect-y! @var{rect} @var{y}
744 Set the bottom Y coordinate of @var{rect} to @var{y}.
747 @deffn {Procedure} set-rect-width! @var{rect} @var{width}
748 Set the width of @var{rect} to @var{width}.
751 @deffn {Procedure} set-rect-height! @var{rect} @var{height}
752 Set the height of @var{rect} to @var{height}.
755 @deffn {Procedure} rect-move! @var{rect} @var{x} @var{y}
756 Move @var{rect} to (@var{x}, @var{y}) in-place.
759 @deffn {Procedure} rect-move-vec2! @var{rect} @var{v}
760 Move @var{rect} to the 2D vector @var{v} in-place.
763 @deffn {Procedure} rect-move-by! @var{rect} @var{x} @var{y}
764 Move @var{rect} by (@var{x}, @var{y}) in-place.
767 @deffn {Procedure} rect-move-by-vec2! @var{rect} @var{v}
768 Move @var{rect} by the 2D vector @var{v} in-place.
771 @deffn {Procedure} rect-inflate! @var{rect} @var{width} @var{height}
772 Expand @var{rect} by @var{width} and @var{height} in-place.
775 @deffn {Procedure} rect-union! @var{rect1} @var{rect2}
776 Modify @var{rect1} in-place to completely cover the area of both
777 @var{rect1} and @var{rect2}.
780 @deffn {Procedure} rect-clip! @var{rect1} @var{rect2}
781 Modify @var{rect1} in-place to be the overlapping region of
782 @var{rect1} and @var{rect2}.
785 @deffn {Procedure} rect-clamp! @var{rect1} @var{rect2}
786 Adjust the location of @var{rect1} in-place so that its bounds are
787 completely within @var{rect2}. An exception is thrown in the case
788 that @var{rect1} cannot fit completely within @var{rect2}.
791 @deffn {Procedure} vec2-clamp-to-rect! @var{v} @var{rect}
792 Restrict the coordinates of the 2D vector @var{v} so that they are
793 within the bounds of @var{rect}. @var{v} is modified in-place.
799 The @code{(chickadee math grid)} module provides a simple spatial
800 partitioning system for axis-aligned bounding boxes
801 (@pxref{Rectangles}) in 2D space. The grid divides the world into
802 tiles and keeps track of which rectangles occupy which tiles. When
803 there are lots of moving objects in the game world that need collision
804 detection, the grid greatly speeds up the process. Instead of
805 checking collisions of each object against every other object (an
806 O(n^2) operation), the grid quickly narrows down which objects could
807 possibly be colliding and only performs collision testing against a
808 small set of objects.
810 In addition to checking for collisions, the grid also handles the
811 resolution of collisions. Exactly how each collision is resolved is
812 user-defined. A player bumping into a wall may slide against it. An
813 enemy colliding with a projectile shot by the player may get pushed
814 back in the opposite direction. Two players colliding may not need
815 resolution at all and will just pass through each other. The way this
816 works is that each time an object (A) is moved within the grid, the
817 grid looks for an object (B) that may possibly be colliding with A. A
818 user-defined procedure known as a ``filter'' is then called with both
819 A and B. If the filter returns @code{#f}, it means that even if A and
820 B are colliding, no collision resolution is needed. In this case the
821 grid won't waste time checking if they really do collide because it
822 doesn't matter. If A and B are collidable, then the filter returns a
823 procedure that implements the resolution technique. The grid will
824 then perform a collision test. If A and B are colliding, the resolver
825 procedure is called. It's the resolvers job to adjust the objects
826 such that they are no longer colliding. The grid module comes with a
827 very simple resolution procedure, @code{slide}, that adjusts object A
828 by the smallest amount so that it no longer overlaps with B. By using
829 this filtering technique, a game can resolve collisions between
830 different objects in different ways.
832 @deffn {Procedure} make-grid [@var{cell-size} 64]
833 Return a new grid partitioned into @var{cell-size} tiles.
836 @deffn {Procedure} grid? @var{obj}
837 Return @code{#t} if @var{obj} is a grid.
840 @deffn {Procedure} cell? @var{obj}
841 Return @code{#t} if @var{obj} is a grid cell.
844 @deffn {Procedure} cell-count @var{cell}
845 Return the number of items in @var{cell}.
848 @deffn {Procedure} grid-cell-size @var{grid}
849 Return the cell size of @var{grid}.
852 @deffn {Procedure} grid-cell-count @var{grid}
853 Return the number of cells currently in @var{grid}.
856 @deffn {Procedure} grid-item-count @var{grid}
857 Return the number of items in @var{grid}.
860 @deffn {Procedure} grid-add @var{grid} @var{item} @var{x} @var{y} @
861 @var{width} @var{height}
863 Add @var{item} to @var{grid} represented by the axis-aligned bounding
864 box whose lower-left corner is at (@var{x}, @var{y}) and is
865 @var{width} x @var{height} in size.
868 @deffn {Procedure} grid-remove @var{grid} @var{item}
869 Return @var{item} from @var{grid}.
872 @deffn {Procedure} grid-clear @var{grid}
873 Remove all items from @var{grid}.
876 @deffn {Procedure} grid-move @var{grid} @var{item} @var{position} @var{filter}
877 Attempt to move @var{item} in @var{grid} to @var{position} (a 2D
878 vector) and check for collisions. For each collision, @var{filter}
879 will be called with two arguments: @var{item} and the item it collided
880 with. If a collision occurs, @var{position} may be modified to
881 resolve the colliding objects.
884 @deffn {Procedure} for-each-cell @var{proc} @var{grid} [@var{rect}]
885 Call @var{proc} with each cell in @var{grid} that intersects
886 @var{rect}, or every cell if @var{rect} is @code{#f}.
889 @deffn {Procedure} for-each-item @var{proc} @var{grid}
890 Call @var{proc} for each item in @var{grid}.
893 @deffn {Procedure} slide @var{item} @var{item-rect} @
894 @var{other} @var{other-rect} @var{goal}
896 Resolve the collision that occurs between @var{item} and @var{other}
897 when moving @var{item-rect} to @var{goal} by sliding @var{item-rect}
898 the minimum amount needed to make it no longer overlap
905 The @code{(chickadee math matrix)} module provides an interface for
906 working with the most common type of matrices in game development: 4x4
907 transformation matrices.
909 @subsubsection Another Note About Performance
911 Much like the vector API, the matrix API is commonly used in
912 performance critical code paths. In order to reduce the amount of
913 garbage generated and improve matrix multiplication performance, there
914 are many procedures that perform in-place modifications of matrix
917 @subsubsection Matrix Operations
919 @deffn {Procedure} make-matrix4 @var{aa} @var{ab} @var{ac} @var{ad} @
920 @var{ba} @var{bb} @var{bc} @var{bd} @
921 @var{ca} @var{cb} @var{cc} @var{cd} @
922 @var{da} @var{db} @var{dc} @var{dd}
924 Return a new 4x4 matrix initialized with the given 16 values in
928 @deffn {Procedure} make-null-matrix4
929 Return a new 4x4 matrix with all values initialized to 0.
932 @deffn {Procedure} make-identity-matrix4
933 Return a new 4x4 identity matrix. Any matrix multiplied by the
934 identity matrix yields the original matrix. This procedure is
935 equivalent to the following code:
938 (make-matrix4 1 0 0 0
946 @deffn {Procedure} matrix4? @var{obj}
947 Return @code{#t} if @var{obj} is a 4x4 matrix.
950 @deffn {Procedure} matrix4* . @var{matrices}
951 Return a new 4x4 matrix containing the product of multiplying all of
952 the given @var{matrices}.
954 Note: Remember that matrix multiplication is @strong{not} commutative!
957 @deffn {Procedure} orthographic-projection @var{left} @var{right} @
958 @var{top} @var{bottom} @
961 Return a new 4x4 matrix that represents an orthographic (2D)
962 projection for the horizontal clipping plane @var{top} and
963 @var{bottom}, the vertical clipping plane @var{top} and @var{bottom},
964 and the depth clipping plane @var{near} and @var{far}.
967 @deffn {Procedure} perspective-projection @var{fov} @
971 Return a new 4x4 matrix that represents a perspective (3D) projection
972 with a field of vision of @var{fov} radians, an aspect ratio of
973 @var{aspect-ratio}, and a depth clipping plane defined by @var{near}
977 @deffn {Procedure} matrix4-translate @var{x}
978 Return a new 4x4 matrix that represents a translation by @var{x}, a 2D
979 vector, a 3D vector, or a rectangle (in which case the bottom-left
980 corner of the rectangle is used).
983 @deffn {Procedure} matrix4-scale @var{s}
984 Return a new 4x4 matrix that represents a scaling along the X, Y, and
985 Z axes by the scaling factor @var{s}, a real number.
988 @deffn {Procedure} matrix4-rotate @var{q}
989 Return a new 4x4 matrix that represents a rotation about an arbitrary
990 axis defined by the quaternion @var{q}.
993 @deffn {Procedure} matrix4-rotate-z @var{theta}
994 Return a new 4x4 matrix that represents a rotation about the Z axis by
998 @deffn {Procedure} matrix4-identity! @var{matrix}
999 Modify @var{matrix} in-place to contain the identity matrix.
1002 @deffn {Procedure} matrix4-mult! @var{dest} @var{a} @var{b}
1003 Multiply the 4x4 matrix @var{a} by the 4x4 matrix @var{b} and store
1004 the result in the 4x4 matrix @var{dest}.
1007 @deffn {Procedure} matrix4-translate! @var{matrix} @var{x}
1008 Modify @var{matrix} in-place to contain a translation by @var{x}, a 2D
1009 vector, a 3D vector, or a rectangle (in which case the bottom-left
1010 corner of the rectangle is used).
1013 @deffn {Procedure} matrix4-scale! @var{matrix} @var{s}
1014 Modify @var{matrix} in-place to contain a scaling along the X, Y, and
1015 Z axes by the scaling factor @var{s}, a real number.
1018 @deffn {Procedure} matrix4-rotate! @var{matrix} @var{q}
1019 Modify @var{matrix} in-place to contain a rotation about an arbitrary
1020 axis defined by the quaternion @var{q}.
1023 @deffn {Procedure} matrix4-rotate-z! @var{matrix} @var{theta}
1024 Modify @var{matrix} in-place to contain a rotation about the Z axis by
1025 @var{theta} radians.
1028 @deffn {Procedure} matrix4-2d-transform! @var{matrix} [#:origin] @
1029 [#:position] [#:rotation] @
1032 Modify @var{matrix} in-place to contain the transformation described
1033 by @var{position}, a 2D vector or rectangle, @var{rotation}, a scalar
1034 representing a rotation about the Z axis, @var{scale}, a 2D vector,
1035 and @var{skew}, a 2D vector. The transformation happens with respect
1036 to @var{origin}, a 2D vector. If an argument is not provided, that
1037 particular transformation will not be included in the result.
1040 @deffn {Procedure} transform! @var{matrix} @var{v}
1041 Modify the 2D vector @var{v} in-place by multiplying it by the 4x4
1042 matrix @var{matrix}.
1046 @subsection Quaternions
1048 In game development, the quaternion is most often used to represent
1049 rotations. Why not use a matrix for that, you may ask. Unlike
1050 matrices, quaternions can be interpolated (animated) and produce a
1051 meaningful result. When interpolating two quaternions, there is a
1052 smooth transition from one rotation to another, whereas interpolating
1053 two matrices would yield garbage.
1055 @deffn {Procedure} quaternion @var{x} @var{y} @var{z} @var{w}
1056 Return a new quaternion with values @var{x}, @var{y}, @var{z}, and
1060 @deffn {Procedure} quaternion? @var{obj}
1061 Return @code{#t} if @var{obj} is a quaternion.
1064 @deffn {Procedure} quaternion-w @var{q}
1065 Return the W component of the quaternion @var{q}.
1068 @deffn {Procedure} quaternion-x @var{q}
1069 Return the X component of the quaternion @var{q}.
1072 @deffn {Procedure} quaternion-y @var{q}
1073 Return the Y component of the quaternion @var{q}.
1076 @deffn {Procedure} quaternion-z @var{q}
1077 Return the Z component of the quaternion @var{q}.
1080 @deffn {Procedure} make-identity-quaternion
1081 Return the identity quaternion.
1087 Easing functions are essential for animation. Each easing function
1088 provides a different path to go from an initial value to a final
1089 value. These functions make an excellent companion to the
1090 @code{tween} procedure (@pxref{Tweening}). Experiment with them to
1091 figure out which function makes an animation look the best.
1093 Pro tip: @code{smoothstep} provides nice results most of the time and
1094 creates smoother animation than using @code{linear}.
1096 @deffn {Procedure} linear @var{t}
1099 @deffn {Procedure} smoothstep @var{t}
1102 @deffn {Procedure} ease-in-quad @var{t}
1105 @deffn {Procedure} ease-out-quad @var{t}
1108 @deffn {Procedure} ease-in-out-quad @var{t}
1111 @deffn {Procedure} ease-in-cubic @var{t}
1114 @deffn {Procedure} ease-out-cubic @var{t}
1117 @deffn {Procedure} ease-in-out-cubic @var{t}
1120 @deffn {Procedure} ease-in-quart @var{t}
1123 @deffn {Procedure} ease-out-quart @var{t}
1126 @deffn {Procedure} ease-in-out-quart @var{t}
1129 @deffn {Procedure} ease-in-quint @var{t}
1132 @deffn {Procedure} ease-out-quint @var{t}
1135 @deffn {Procedure} ease-in-out-quint @var{t}
1138 @deffn {Procedure} ease-in-sine @var{t}
1141 @deffn {Procedure} ease-out-sine @var{t}
1144 @deffn {Procedure} ease-in-out-sine @var{t}
1148 @subsection Bezier Curves
1150 The @code{(chickadee math bezier)} module provides an API for
1151 describing cubic Bezier curves in 2D space. These curves are notably
1152 used in font description, vector graphics programs, and when it comes
1153 to games: path building. With Bezier curves, it's somewhat easy to
1154 create a smooth looking path for an enemy to move along, for example.
1155 Bezier curves become particularly interesting when they are chained
1156 together to form a Bezier ``path'', where the end point of one curve
1157 becomes the starting point of the next.
1159 Currently, the rendering of Bezier curves is rather crude and provided
1160 mostly for visualizing and debugging curves that would be unseen in
1161 the final game. See @xref{Lines and Shapes} for more information.
1163 @deffn {Procedure} make-bezier-curve @var{p0} @var{p1} @var{p2} @var{p3}
1164 Return a new Bezier curve object whose starting point is @var{p0},
1165 ending point is @var{p3}, and control points are @var{p1} and
1166 @var{p2}. All points are 2D vectors.
1169 @deffn {Procedure} bezier-curve? @var{obj}
1170 Return @code{#t} if @var{obj} is a Bezier curve.
1173 @deffn {Procedure} bezier-curve-p0 @var{bezier}
1174 Return the starting point of @var{bezier}.
1177 @deffn {Procedure} bezier-curve-p1 @var{bezier}
1178 Return the first control point of @var{bezier}.
1181 @deffn {Procedure} bezier-curve-p2 @var{bezier}
1182 Return the second control point of @var{bezier}.
1185 @deffn {Procedure} bezier-curve-p3 @var{bezier}
1186 Return the end point of @var{bezier}.
1189 @deffn {Procedure} bezier-path . @var{control-points}
1190 Return a list of connected bezier curves defined by
1191 @var{control-points}. The first curve is defined by the first 4
1192 arguments and every additional curve thereafter requires 3 additional
1196 @deffn {Procedure} bezier-curve-point-at @var{bezier} @var{t}
1197 Return the coordinates for @var{bezier} at @var{t} (a value in the
1198 range [0, 1] representing how far from the start of the curve to
1199 check) as a 2D vector.
1202 @deffn {Procedure} bezier-curve-point-at! @var{dest} @var{bezier} @var{t}
1203 Modify the 2D vector @var{dest} in-place to contain the coordinates
1204 for @var{bezier} at @var{t}.
1208 @subsection Path Finding
1210 Most game worlds have maps. Often, these games have a need to move
1211 non-player characters around in an unscripted fashion. For example,
1212 in a real-time strategy game, the player may command one of their
1213 units to attack something in the enemy base. To do so, the unit must
1214 calculate the shortest route to get there. It wouldn't be a very fun
1215 game if units didn't know how to transport themselves efficiently.
1216 This is where path finding algorithms come in handy. The
1217 @code{(chickadee math path-finding)} module provides a generic
1218 implementation of the popular A* path finding algorithm. Just add a
1221 The example below defines a very simple town map and finds the
1222 quickest way to get from the town common to the school.
1226 '((town-common . (town-hall library))
1227 (town-hall . (town-common school))
1228 (library . (town-common cafe))
1229 (school . (town-hall cafe))
1230 (cafe . (library school))))
1231 (define (neighbors building)
1232 (assq-ref town-map building))
1233 (define (cost a b) 1)
1234 (define (distance a b) 1)
1235 (define pf (make-path-finder))
1236 (a* pf 'town-common 'school neighbors cost distance)
1239 In this case, the @code{a*} procedure will return the list
1240 @code{(town-common town-hall school)}, which is indeed the shortest
1241 route. (The other possible route is @code{(town-common library cafe
1244 The @code{a*} procedure does not know anything about about any kind of
1245 map and therefore must be told how to look up neighboring nodes, which
1246 is what the @code{neighbors} procedure in the example does. To
1247 simulate different types of terrain, a cost procedure is used. In
1248 this example, it is just as easy to move between any two nodes because
1249 @code{cost} always returns 1. In a real game, perhaps moving from
1250 from a field to a rocky hill would cost a lot more than moving from
1251 one field to another. Finally, a heuristic is used to calculate an
1252 approximate distance between two nodes on the map. In this simple
1253 association list based graph it is tough to calculate a distance
1254 between nodes, so the @code{distance} procedure isn't helpful and
1255 always returns 1. In a real game with a tile-based map, for example,
1256 the heuristic could be a quick Manhattan distance calculation based on
1257 the coordinates of the two map tiles. Choose an appropriate heuristic
1258 for optimal path finding!
1260 @deffn {Procedure} make-path-finder
1261 Return a new path finder object.
1264 @deffn {Procedure} path-finder? @var{obj}
1265 Return @code{#t} if @var{obj} is a path finder.
1268 @deffn {Procedure} a* @var{path-finder} @var{start} @var{goal} @
1269 @var{neighbors} @var{cost} @var{distance}
1271 Return a list of nodes forming a path from @var{start} to @var{goal}
1272 using @var{path-finder} to hold state. @var{neighbors} is a procedure
1273 that accepts a node and returns a list of nodes that neighbor it.
1274 @var{cost} is a procedure that accepts two neighboring nodes and
1275 returns the cost of moving from the first to the second as a real
1276 number. @var{distance} is a procedure that accepts two nodes and
1277 returns an approximate distance between them.
1283 Chickadee aims to make hardware-accelerated graphics rendering as
1284 simple and efficient as possible by providing high-level APIs that
1285 interact with the low-level OpenGL API under the hood. Anyone that
1286 has worked with OpenGL directly knows that it has a steep learning
1287 curve and a lot of effort is needed to render even a single triangle.
1288 The Chickadee rendering engine attempts to make it easy to do common
1289 tasks like rendering a sprite while also providing all of the building
1290 blocks to implement additional rendering techniques.
1293 * Textures:: 2D images.
1294 * Sprites:: Draw 2D images.
1295 * Tile Maps:: Draw 2D tile maps.
1296 * Lines and Shapes:: Draw line segments and polygons.
1297 * Fonts:: Drawing text.
1298 * Particles:: Pretty little flying pieces!
1299 * Blending:: Control how pixels are combined.
1300 * Framebuffers:: Render to texture.
1301 * Viewports:: Restrict rendering to a particular area.
1302 * Rendering Engine:: Rendering state management.
1303 * Buffers:: Send data to the GPU.
1304 * Shaders:: Create custom GPU programs.
1308 @subsection Textures
1310 @deffn {Procedure} load-image @var{file} [#:min-filter nearest] @
1311 [#:mag-filter nearest] [#:wrap-s repeat] [#:wrap-t repeat]
1313 Load the image data from @var{file} and return a new texture object.
1315 @var{min-filter} and @var{mag-filter} describe the method that should
1316 be used for minification and magnification when rendering,
1317 respectively. Possible values are @code{nearest} and @code{linear}.
1319 @var{wrap-s} and @var{wrap-t} describe how to interpret texture
1320 coordinates that are greater than @code{1.0}. Possible values are
1321 @code{repeat}, @code{clamp}, @code{clamp-to-border}, and
1322 @code{clamp-to-edge}.
1329 For those who are new to this game, a sprite is a 2D rectangular
1330 bitmap that is rendered to the screen. For 2D games, sprites are the
1331 most essential graphical abstraction. They are used for drawing maps,
1332 players, NPCs, items, particles, text, etc. In Chickadee, bitmaps are
1333 stored in textures (@pxref{Textures}) and can be used to draw sprites
1334 via the @code{draw-sprite} procedure.
1336 @deffn {Procedure} draw-sprite @var{texture} @var{position} @
1337 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1340 Draw @var{texture} at @var{position}.
1342 Optionally, other transformations may be applied to the sprite.
1343 @var{rotation} specifies the angle to rotate the sprite, in radians.
1344 @var{scale} specifies the scaling factor as a 2D vector. All
1345 transformations are applied relative to @var{origin}, a 2D vector,
1346 which defaults to the lower-left corner.
1348 Alpha blending is used by default but the blending method can be
1349 changed by specifying @var{blend-mode}.
1351 The area drawn to is as big as the texture, by default. To draw to an
1352 arbitrary section of the screen, specify @var{rect}.
1354 Finally, advanced users may specify @var{shader} to change the way the
1355 sprite is rendered entirely.
1358 It's not uncommon to need to draw hundreds or thousands of sprites
1359 each frame. However, GPUs (graphics processing units) are tricky
1360 beasts that prefer to be sent few, large chunks of data to render
1361 rather than many, small chunks. Using @code{draw-sprite} on its own
1362 will involve at least one GPU call @emph{per sprite}, which will
1363 quickly lead to poor performance. To deal with this, a technique
1364 known as ``sprite batching'' can be used. Instead of drawing each
1365 sprite immediately, the sprite batch will build up a large of buffer
1366 of sprites to draw and defer rendering until the last possible moment.
1367 Batching isn't a panacea, though. Batching only works if the sprites
1368 being drawn share as much in common as possible. Every time you draw
1369 a sprite with a different texture or blend mode, the batch will be
1370 sent off to the GPU. Therefore, batching is most useful if you
1371 minimize such changes. A good strategy for reducing texture changes
1372 is to stuff many bitmaps into a single image file and create a
1373 ``texture atlas'' (@pxref{Textures}) to access the sub-images within.
1375 Taking advantage of sprite batching in Chickadee is easy, just wrap
1376 the code that is calling @code{draw-sprite} a lot in the
1377 @code{with-batched-sprites} form.
1379 @deffn {Syntax} with-batched-sprites @var{body} @dots{}
1380 Use batched rendering for all @code{draw-sprite} calls within
1384 With a basic sprite abstraction in place, it's possible to build other
1385 abstractions on top of it. One such example is the ``nine patch''. A
1386 nine patch is a sprite that can be rendered at various sizes without
1387 becoming distorted. This is achieved by dividing up the sprite into
1392 the center, which can be scaled horizontally and vertically
1394 the four corners, which can never be scaled
1396 the left and right sides, which can be scaled vertically
1398 the top and bottom sides, which can be scaled horizontally
1401 The one caveat is that the bitmap regions must be designed in such a
1402 way so that they are not distorted when stretched along the affected
1403 axes. For example, that means that the top and bottom sides could
1404 have varying colored pixels vertically, but not horizontally.
1406 The most common application of this technique is for graphical user
1407 interface widgets like buttons and dialog boxes. By using a nine
1408 patch, they can be rendered at any size without unappealing scaling
1411 @deffn {Procedure} draw-nine-patch @var{texture} @var{rect} @
1412 [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] @
1413 [#:left-margin margin] [#:right-margin margin] @
1414 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1417 Draw a nine patch sprite. A nine patch sprite renders @var{texture}
1418 as a @var{width} x @var{height} rectangle whose stretchable areas are
1419 defined by the given margin measurements @var{top-margin},
1420 @var{bottom-margin}, @var{left-margin}, and @var{right-margin}. The
1421 @var{margin} argument may be used to configure all four margins at
1424 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1425 the other arguments.
1429 @subsection Tile Maps
1431 A tile map is a scene created by composing lots of small sprites,
1432 called ``tiles'', into a larger image. One program for editing such
1433 maps is called @url{http://mapeditor.org,Tiled}. Chickadee has native
1434 support for loading and rendering Tiled maps in the @code{(chickadee
1435 render tiled)} module.
1437 @deffn {Procedure} load-tile-map @var{file-name}
1438 Load the Tiled formatted map in @var{file-name} and return a new tile
1442 @deffn {Procedure} draw-tile-map @var{tile-map} [#:layers] [#:region] @
1443 [#:origin] [#:position] [#:scale] [#:rotation]
1445 Draw the layers of @var{tile-map}. By default, all layers are drawn.
1446 To draw a subset of the available layers, pass a list of layer ids
1447 using the @var{layers} keyword argument.
1449 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1450 the other arguments.
1453 @node Lines and Shapes
1454 @subsection Lines and Shapes
1456 Sprites are fun, but sometimes simple, untextured lines and polygons
1457 are desired. That's where the @code{(chickadee render shapes)} module
1460 @deffn {Procedure} draw-line @var{start} @var{end} @
1461 [#:thickness 0.5] [#:feather 1.0] [#:cap round] [#:color] @
1464 Draw a line segment from @var{start} to @var{end}. The line will be
1465 @var{thickness} pixels thick with an antialiased border @var{feather}
1466 pixels wide. The line will be colored @var{color}. @var{cap}
1467 specifies the type of end cap that should be used to terminate the
1468 lines, either @code{none}, @code{butt}, @code{square}, @code{round},
1469 @code{triangle-in}, or @code{triangle-out}. Advanced users may use
1470 the @var{shader} argument to override the built-in line segment
1474 @deffn {Procedure} draw-bezier-curve @var{bezier} [#:segments 32] @
1475 [#:control-points?] [#:tangents?] @
1476 [#:control-point-size 8] @
1477 [#:control-point-color yellow] @
1478 [#:tangent-color yellow] @
1479 [#:thickness 0.5] [#:feather 1.0] @
1482 Draw the curve defined by @var{bezier} using a resolution of N
1483 @var{segments}. When @var{control-points?} is @code{#t}, the control
1484 points are rendered as squares of size @var{control-point-size} pixels
1485 and a color of @var{control-point-color}. When @var{tangents?} is
1486 @code{#t}, the tangent lines from terminal point to control point are
1487 rendered using the color @var{tangent-color}.
1489 All line segments rendered use @code{draw-line}, and thus the
1490 arguments @var{thickness} and @var{feather} have the same effect as in
1493 A custom @var{matrix} may be passed for applications that require more
1494 control over the final output.
1497 @deffn {Procedure} draw-bezier-path @var{path} [#:segments 32] @
1498 [#:control-points?] [#:tangents?] @
1499 [#:control-point-size 8] @
1500 [#:control-point-color yellow] @
1501 [#:tangent-color yellow] @
1502 [#:thickness 0.5] [#:feather 1.0] @
1505 Render @var{path}, a list of bezier curves. See the documentation for
1506 @code{draw-bezier-curve} for an explanation of all the keyword
1513 Printing text to the screen is quite easy:
1516 (draw-text "Hello, world" (vec2 100.0 100.0))
1519 Chickadee loads and renders bitmap fonts in the
1520 @url{http://www.angelcode.com/products/bmfont/doc/file_format.html,
1521 Angel Code format}. A default font named ``Good Neighbors'' is
1522 built-in to Chickadee and is used for all text rendering operations
1523 where a font is not specified, as is the case in the above example.
1525 The following procedures can be found in the @code{(chickadee render
1528 @deffn {Procedure} load-font @var{file}
1529 Load the Angel Code font (in either XML or FNT format) in @var{file}
1530 and return a new font object.
1533 @deffn {Procedure} font? @var{obj}
1534 Return @code{#t} if @var{obj} is a font object.
1537 @deffn {Procedure} font-face @var{font}
1538 Return the name of @var{font}.
1541 @deffn {Procedure} font-line-height @var{font}
1542 Return the line height of @var{font}.
1545 @deffn {Procedure} font-line-height @var{font}
1546 Return the line height of @var{font}.
1549 @deffn {Procedure} font-bold? @var{font}
1550 Return @code{#t} if @var{font} is a bold font.
1553 @deffn {Procedure} font-italic? @var{font}
1554 Return @code{#t} if @var{font} is an italicized font.
1557 @deffn {Procedure} draw-text @var{text} @var{position}
1558 [#:font] [#:origin] [#:scale] [#:rotation] [#:blend-mode]
1559 [#:start 0] [#:end @code{(string-length text)}]
1561 Draw the string @var{text} with the first character starting at
1562 @var{position} using @var{font}. If @var{font} is not specified, a
1563 built-in font is used.
1566 (draw-text font "Hello, world!" (vec2 128.0 128.0))
1569 To render a substring of @var{text}, use the @var{start} and @var{end}
1572 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1573 the other arguments.
1577 @subsection Particles
1579 Effects like smoke, fire, sparks, etc. are often achieved by animating
1580 lots of little, short-lived sprites known as ``particles''. In fact,
1581 all of these effects, and more, can be accomplished by turning a few
1582 configuration knobs in a ``particle system''. A particle system takes
1583 care of managing the many miniscule moving morsels so the developer
1584 can quickly produce an effect and move on with their life. The
1585 @code{(chickadee render particles)} module provides an API for
1586 manipulating particle systems.
1588 Below is an example of a very simple particle system that utilizes
1589 nearly all of the default configuration settings:
1592 (use-modules (chickadee render particles))
1593 (define texture (load-image "particle.png"))
1594 (define particles (make-particles 2000 #:texture texture))
1597 In order to put particles into a particle system, a particle
1598 ``emitter'' is needed. Emitters know where to spawn new particles,
1599 how many of them to spawn, and for how long they should do it.
1601 Below is an example of an emitter that spawns 16 particles per frame
1602 at the coordinates @code{(320, 240)}:
1605 (use-modules (chickadee math vector))
1606 (define emitter (make-particle-emitter (vec2 320.0 240.0) 16))
1607 (add-particle-emitter particles emitter)
1610 To see all of the tweakable knobs and switches, read on!
1612 @deffn {Procedure} make-particles @var{capacity} [#:blend-mode @code{alpha}] @
1613 [#:color white] [#:end-color transparent] [#:texture] @
1614 [#:animation-rows 1] [#:animation-columns 1] [#:width] [#:height] @
1615 [#:speed-range (vec2 0.1 1.0)] [#:acceleration-range (vec2 0.0 0.1)] @
1616 [#:direction-range (vec2 0 (* 2 pi))] [#:lifetime 30] [#:sort]
1618 Return a new particle system that may contain up to @var{capacity}
1619 particles. Achieving the desired particle effect involves tweaking
1620 the following keyword arguments as needed:
1622 - @var{blend-mode}: Pixel blending mode. @code{alpha} by default.
1623 (@pxref{Blending} for more about blend modes).
1625 - @var{start-color}: The tint color of the particle at the beginning of its
1626 life. White by default.
1628 - @var{end-color}: The tint color of the particle at the end of of its
1629 life. Completely transparent by default for a fade-out effect. The
1630 color in the middle of a particle's life will be an interpolation of
1631 @var{start-color} and @var{end-color}.
1633 - @var{texture}: The texture applied to the particles. The texture
1634 may be subdivided into many animation frames.
1636 - @var{animation-rows}: How many animation frame rows there are in the
1637 texture. Default is 1.
1639 - @var{animation-columns}: How many animation frame columns there are
1640 in the texture. Default is 1.
1642 - @var{width}: The width of each particle. By default, the width of
1643 an animation frame (in pixels) is used.
1645 - @var{height}: The height of each particle. By default, the height
1646 of an animation frame (in pixels) is used.
1648 - @var{speed-range}: A 2D vector containing the min and max particle
1649 speed. Each particle will have a speed chosen at random from this
1650 range. By default, speed ranges from 0.1 to 1.0.
1652 - @var{acceleration-range}: A 2D vector containing the min and max
1653 particle acceleration. Each particle will have an acceleration chosen
1654 at random from this range. By default, acceleration ranges from 0.0
1657 - @var{direction-range}: A 2D vector containing the min and max
1658 particle direction as an angle in radians. Each particle will have a
1659 direction chosen at random from this range. By default, the range
1660 covers all possible angles.
1662 - @var{lifetime}: How long each particle lives, measured in
1663 updates. 30 by default.
1665 - @var{sort}: @code{youngest} if youngest particle should be drawn
1666 last or @code{oldest} for the reverse. By default, no sorting is
1670 @deffn {Procedure} particles? @var{obj}
1671 Return @code{#t} if @var{obj} is a particle system.
1674 @deffn {Procedure} update-particles @var{particles}
1675 Advance the simulation of @var{particles}.
1678 @deffn {Procedure} draw-particles @var{particles}
1679 Render @var{particles}.
1682 @deffn {Procedure} draw-particles* @var{particles} @var{matrix}
1683 Render @var{particles} with @var{matrix} applied.
1686 @deffn {Procedure} make-particle-emitter @var{spawn-area} @
1687 @var{rate} [@var{duration}]
1689 Return a new particle emitter that spawns @var{rate} particles per
1690 frame within @var{spawn-area} (a rectangle or 2D vector) for
1691 @var{duration} frames. If @var{duration} is not specified, the
1692 emitter will spawn particles indefinitely.
1695 @deffn {Procedure} particle-emitter? @var{obj}
1696 Return @code{#t} if @var{obj} is a particle emitter.
1699 @deffn {Procedure} particle-emitter-spawn-area @var{emitter}
1700 Return the spawn area for @var{emitter}.
1703 @deffn {Procedure} particle-emitter-rate @var{emitter}
1704 Return the number of particles that @var{emitter} will spawn per
1708 @deffn {Procedure} particle-emitter-life @var{emitter}
1709 Return the number of frames remaining in @var{emitter}'s lifespan.
1712 @deffn {Procedure} particle-emitter-done? @var{emitter}
1713 Return @code{#t} if @var{emitter} has finished spawning particlces.
1716 @deffn {Procedure} add-particle-emitter @var{particles} @var{emitter}
1717 Add @var{emitter} to @var{particles}.
1720 @deffn {Procedure} remove-particle-emitter @var{particles} @var{emitter}
1721 Remove @var{emitter} to @var{particles}
1725 @subsection Blending
1727 Rendering a scene often involves drawing layers of objects that
1728 overlap each other. Blending determines how two overlapping pixels
1729 are combined in the final image that is rendered to the screen.
1730 Chickadee provides the following blend modes:
1734 @item @code{replace}
1735 Use the latest color, ignoring all others.
1738 Blend pixels according to the values of their alpha channels. This is
1739 the most commonly used blend mode and thus is Chickadee's default
1743 Add all pixel color values together. The more colors blended
1744 together, the more white the final color becomes.
1746 @item @code{subtract}
1747 Subtract all pixel color values. The more colors blended together,
1748 the more black the final color becomes.
1750 @item @code{multiply}
1754 @item @code{lighten}
1761 @subsection Framebuffers
1763 A framebuffer is a chunk of memory that the GPU can render things
1764 onto. By default, the framebuffer that is used for rendering is the
1765 one belonging to the game window, but custom framebuffers can be used
1766 as well. A common use-case for custom framebuffers is applying
1767 post-processing effects: The entire scene is rendered to a
1768 framebuffer, and then the contents of that framebuffer are applied to
1769 a post-processing shader and rendered to the game window. The
1770 post-processing shader could do any number of things: scaling,
1771 antialiasing, motion blur, etc.
1773 @deffn {Procedure} make-framebuffer @var{width} @var{height} [#:min-filter 'linear] [#:mag-filter 'linear] [#:wrap-s 'repeat] [#:wrap-t 'repeat]
1775 Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high.
1777 @var{min-filter} and @var{mag-filter} determine the scaling algorithm
1778 applied to the framebuffer when rendering. By default, linear scaling
1779 is used in both cases. To perform no smoothing at all, use
1780 @code{nearest} for simple nearest neighbor scaling. This is typically
1781 the best choice for pixel art games.
1784 @deffn {Procedure} framebuffer? @var{obj}
1785 Return @code{#t} if @var{obj} is a framebuffer.
1788 @deffn {Procedure} framebuffer-texture @var{fb}
1789 Return the texture backing the framebuffer @var{fb}.
1792 @deffn {Procedure} framebuffer-viewport @var{fb}
1793 Return the default viewport (@pxref{Viewports}) used by the
1794 framebuffer @var{fb}.
1797 @deffn {Procedure} null-framebuffer
1798 The default framebuffer.
1802 @subsection Viewports
1804 A viewport represents a subset of the screen (or framebuffer). When
1805 rendering a frame, the resulting image will only appear within that
1806 viewport. These aren't often needed, and Chickadee's default viewport
1807 occupies the entire screen, but there are certain situations where
1808 they are useful. For example, a split-screen multiplayer game may
1809 render to two different viewports, each occupying a different half of
1810 the screen. For information about how to set the current viewport,
1811 see @code{with-viewport} in @ref{Rendering Engine}.
1813 The @code{(chickadee render viewport)} module provides the following
1816 @deffn {Procedure} make-viewport @var{x} @var{y} @var{width} @var{height} @
1817 [#:clear-color] [#:clear-flags]
1819 Create a viewport that covers an area of the window starting from
1820 coordinates (@var{x}, @var{y}) and spanning @var{width} @code{x}
1821 @var{height} pixels. Fill the viewport with @var{clear-color} when
1822 clearing the screen. Clear the buffers denoted by the list of symbols
1823 in @var{clear-flags}.
1825 Possible values for @var{clear-flags} are @var{color-buffer},
1826 @var{depth-buffer}, @var{accum-buffer}, and @var{stencil-buffer}.
1829 @deffn {Procedure} viewport? @var{obj}
1830 Return @code{#t} if @var{obj} is a viewport.
1833 @deffn {Procedure} viewport-x @var{viewport}
1834 Return the left edge of @var{viewport}.
1837 @deffn {Procedure} viewport-y @var{viewport}
1838 Return the bottom edge of @var{viewport}.
1841 @deffn {Procedure} viewport-width @var{viewport}
1842 Return the width of @var{viewport}.
1845 @deffn {Procedure} viewport-height @var{viewport}
1846 Return the height of @var{viewport}.
1849 @deffn {Procedure} viewport-clear-color @var{viewport}
1850 Return the clear color for @var{viewport}.
1853 @deffn {Procedure} viewport-clear-flags @var{viewport}
1854 Return the list of clear flags for @var{viewport}.
1857 @node Rendering Engine
1858 @subsection Rendering Engine
1860 Chickadee defines rendering using a metaphor familiar to Scheme
1861 programmers: procedure application. A shader (@pxref{Shaders}) is
1862 like a procedure for the GPU to apply. Shaders are passed arguments:
1863 A vertex array containing the geometry to render (@pxref{Buffers}) and
1864 zero or more keyword arguments that the shader understands. Similar
1865 to how Scheme has @code{apply} for calling procedures, Chickadee
1866 provides @code{gpu-apply} for calling shaders.
1868 Additionally, there is some dynamic state that effects how
1869 @code{gpu-apply} will behave. Things like the current viewport,
1870 framebuffer, and blend mode are stored as dynamic state because it
1871 would be tedious to have to have to specify them each time
1872 @code{gpu-apply} is called.
1874 The following procedures and syntax can be found in the
1875 @code{(chickadee render)} module.
1877 @deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
1878 [#:uniform-key @var{uniform-value} ...]
1879 @deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
1880 @var{count} [#:uniform-key @var{uniform-value} ...]
1882 Render @var{vertex-array} using @var{shader} with the uniform values
1883 specified in the following keyword arguments.
1885 While @code{gpu-apply} will draw every vertex in @var{vertex-array},
1886 @code{gpu-apply*} will only draw @var{count} vertices.
1889 @deffn {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
1890 @var{n} [#:uniform-key @var{uniform-value} ...]
1891 @deffnx {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
1892 @var{count} @var{n} [#:uniform-key @var{uniform-value} ...]
1894 Render @var{vertex-array} @var{n} times using @var{shader} with the
1895 uniform values specified in the following keyword arguments.
1897 Instanced rendering is very beneficial for rendering the same object
1898 many times with only small differences for each one. For example, the
1899 particle effects described in @ref{Particles} use instanced rendering.
1901 While @code{gpu-apply/instanced} will draw every vertex in
1902 @var{vertex-array}, @code{gpu-apply*} will only draw @var{count}
1906 @deffn {Procedure} current-viewport
1907 Return the currently bound viewport (@pxref{Viewports}).
1910 @deffn {Procedure} current-framebuffer
1911 Return the currently bound framebuffer (@pxref{Framebuffers}).
1914 @deffn {Procedure} current-blend-mode
1915 Return the currently bound blend mode (@pxref{Blending}).
1918 @deffn {Procedure} current-depth-test
1919 Return @code{#t} if depth testing is currently enabled (@pxref{Blending}).
1922 @deffn {Procedure} current-texture
1923 Return the currently bound texture (@pxref{Textures}).
1926 @deffn {Procedure} current-projection
1927 Return the currently bound projection matrix (@pxref{Matrices}).
1930 @deffn {Syntax} with-viewport @var{viewport} @var{body} ...
1931 Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
1934 @deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
1935 Evaluate @var{body} with the current framebuffer bound to
1936 @var{framebuffer} (@pxref{Framebuffers}).
1939 @deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
1940 Evaluate @var{body} with the current blend mode bound to
1941 @var{blend-mode} (@pxref{Blending}).
1944 @deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
1945 Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
1946 is @code{#f}, or enabled otherwise (@pxref{Blending}).
1949 @deffn {Syntax} with-texture @var{texture} @var{body} ...
1950 Evaluate @var{body} with the current texture bound to @var{texture}
1954 @deffn {Syntax} with-projection @var{projection} @var{body} ...
1955 Evaluate @var{body} with the current projection matrix bound to
1956 @var{projection} (@pxref{Matrices}).
1962 Alright, let's brush aside all of those pretty high level abstractions
1963 and discuss what is going on under the hood. The GPU exists as a
1964 discrete piece of hardware separate from the CPU. In order to make it
1965 draw things, we must ship lots of data out of our memory space and
1966 into the GPU. The @code{(chickadee render buffer}) module provides an
1967 API for manipulating GPU buffers.
1969 In OpenGL terminology, a chunk of data allocated on the GPU is a
1970 ``vertex buffer object'' or VBO. For example, here is a bytevector
1971 that could be transformed into a GPU buffer that packs together vertex
1972 position and texture coordinates:
1975 (use-modules (chickadee render buffer) (srfi srfi-4))
1977 (f32vector -8.0 -8.0 ; 2D vertex
1978 0.0 0.0 ; 2D texture coordinate
1979 8.0 -8.0 ; 2D vertex
1980 1.0 0.0 ; 2D texture coordinate
1982 1.0 1.0 ; 2D texture coordinate
1983 -8.0 8.0 ; 2D vertex
1984 0.0 1.0)) ; 2D texture coordinate
1987 This data represents a textured 16x16 square centered on the
1988 origin. To send this data to the GPU, the @code{make-buffer} procedure
1992 (define buffer (make-buffer data #:stride 16))
1995 The @code{#:stride} keyword argument indicates how many bytes make up
1996 each element of the buffer. In this case, there are 4 floats per
1997 element: 2 for the vertex, and 2 for the texture coordinate. A 32-bit
1998 float is 4 bytes in length, so the buffer's stride is 16.
2000 Within a VBO, one or more ``attributes'', as OpenGL calls them, may be
2001 present. Attributes are subregions within the buffer that have a
2002 particular data type. In this case, there are two attributes packed
2003 into the buffer. To provided a typed view into a buffer, the
2004 @code{make-typed-buffer} procedure is needed:
2008 (make-typed-buffer #:buffer buffer
2010 #:component-type 'float
2013 (make-typed-buffer #:buffer buffer
2015 #:component-type 'float
2020 To render a square, the GPU needs to draw two triangles, which means
2021 we need 6 vertices in total. However, the above buffer only contains
2022 data for 4 vertices. This is becase there are only 4 unique vertices
2023 for a square, but 2 of them must be repeated for each triangle. To
2024 work with deduplicated vertex data, an ``index buffer'' must be
2028 (define index-buffer
2029 (make-buffer (u32vector 0 3 2 0 2 1)
2032 (make-typed-buffer #:type 'scalar
2033 #:component-type 'unsigned-int
2034 #:buffer index-buffer))
2037 Note the use of the @code{#:target} keyword argument. It is required
2038 because the GPU treats index data in a special way and must be told
2039 which data is index data.
2041 Now that the typed buffers representing each attribute have been
2042 created, all that's left is to bind them all together in a ``vertex
2043 array object'', or VAO. Vertex arrays associate each typed buffer
2044 with an attribute index on the GPU. The indices that are chosen must
2045 correspond with the indices that the shader (@pxref{Shaders}) expects
2049 (define vertex-array
2050 (make-vertex-array #:indices indices
2051 #:attributes `((0 . ,vertices)
2055 With the vertex array created, the GPU is now fully aware of how to
2056 interpret the data that it has been given in the original buffer.
2057 Actually rendering this square is left as an exercise to the reader.
2058 See the @ref{Shaders} section and the @code{gpu-apply} procedure in
2059 @ref{Rendering Engine} for the remaining pieces of a successful draw
2060 call. Additionally, consider reading the source code for sprites,
2061 shapes, or particles to see GPU buffers in action.
2063 Without further ado, the API reference:
2065 @deffn {Procedure} make-buffer @var{data} [#:name "anonymous"] @
2066 [#:length] [#:offset 0] [#:stride 0] [#:target @code{vertex}] @
2067 [#:usage @code{static}]
2069 Upload @var{data}, a bytevector, to the GPU. By default, the entire
2070 bytevector is uploaded. A subset of the data may be uploaded by
2071 specifying the @var{offset}, the index of the first byte to be
2072 uploaded, and @var{length}, the number of bytes to upload.
2074 If @var{data} is @code{#f}, allocate @var{length} bytes of fresh GPU
2077 @var{target} and @var{usage} are hints that tell the GPU how the
2078 buffer is intended to be used.
2080 @var{target} may be:
2084 Vertex attribute data.
2095 The buffer data will not be modified after creation.
2098 The buffer data will be modified frequently.
2102 @var{name} is simply an arbitrary string for debugging purposes that
2103 is never sent to the GPU.
2106 @deffn {Procedure} buffer? @var{obj}
2107 Return @code{#t} if @var{obj} is a GPU buffer.
2110 @deffn {Procedure} index-buffer? @var{buffer}
2111 Return @code{#t} if @var{buffer} is an index buffer.
2115 Represents the absence of a buffer.
2118 @deffn {Procedure} buffer-name @var{buffer}
2119 Return the name of @var{buffer}.
2122 @deffn {Procedure} buffer-length @var{buffer}
2123 Return the length of @var{buffer}.
2126 @deffn {Procedure} buffer-stride @var{buffer}
2127 Return the amount of space, in bytes, between each element in
2131 @deffn {Procedure} buffer-target @var{buffer}
2132 Return the the intended usage of @var{buffer}, either @code{vertex} or
2136 @deffn {Procedure} buffer-usage @var{buffer}
2137 Return the intended usage of @var{buffer}, either @code{static} for
2138 buffer data that will not change once sent to the GPU, or
2139 @code{stream} for buffer data that will be frequently updated from the
2143 @deffn {Procedure} buffer-data @var{buffer}
2144 Return a bytevector containing all the data within @var{buffer}. If
2145 @var{buffer} has not been mapped (see @code{with-mapped-buffer}) then
2146 this procedure will return @code{#f}.
2149 @deffn {Syntax} with-mapped-buffer @var{buffer} @var{body} @dots{}
2150 Evaluate @var{body} in the context of @var{buffer} having its data
2151 synced from GPU memory to RAM. In this context, @code{buffer-data}
2152 will return a bytevector of all the data stored in @var{buffer}. When
2153 program execution exits this form, the data (including any
2154 modifications) is synced back to the GPU.
2156 This form is useful for streaming buffers that need to update their
2157 contents dynamically, such as a sprite batch.
2160 @deffn {Procedure} make-typed-buffer #:buffer #:type @
2161 #:component-type #:length [#:offset 0] [#:divisor] @
2162 [#:name "anonymous"]
2164 Return a new typed buffer view for @var{buffer} starting at byte index
2165 @var{offset} of @var{length} elements, where each element is of
2166 @var{type} and composed of @var{component-type} values.
2168 Valid values for @var{type} are:
2193 Valid values for @var{component-type} are:
2198 @item @code{unsigned-byte}
2200 @item @code{unsigned-short}
2202 @item @code{unsigned-int}
2208 @var{divisor} is only needed for instanced rendering applications (see
2209 @code{gpu-apply/instanced} in @ref{Rendering Engine}) and represents
2210 how many instances each vertex element applies to. A divisor of 0
2211 means that a single element is used for every instance and is used for
2212 the data being instanced. A divisor of 1 means that each element is
2213 used for 1 instance. A divisor of 2 means that each element is used
2214 for 2 instances, and so on.
2217 @deffn {Procedure} typed-buffer? @var{obj}
2218 Return @code{#t} if @var{obj} is a typed buffer.
2221 @deffn {Procedure} typed-buffer->buffer @var{typed-buffer}
2222 Return the buffer that @var{typed-buffer} is using.
2225 @deffn {Procedure} typed-buffer-name @var{typed-buffer}
2226 Return the name of @var{typed-buffer}.
2229 @deffn {Procedure} typed-buffer-offset @var{typed-buffer}
2230 Return the byte offset of @var{typed-buffer}.
2233 @deffn {Procedure} typed-buffer-type @var{typed-buffer}
2234 Return the data type of @var{typed-buffer}.
2237 @deffn {Procedure} typed-buffer-component-type @var{typed-buffer}
2238 Return the component data type of @var{typed-buffer}
2241 @deffn {Procedure} typed-buffer-divisor @var{typed-buffer}
2242 Return the instance divisor for @var{typed-buffer}.
2245 @deffn {Syntax} with-mapped-typed-buffer @var{typed-buffer} @var{body} @dots{}
2247 Evaluate @var{body} in the context of @var{typed-buffer} having its
2248 data synced from GPU memory to RAM. See @code{with-mapped-buffer} for
2252 @deffn {Procedure} make-vertex-array #:indices #:attributes @
2253 [#:mode @code{triangles}]
2255 Return a new vertex array using the index data within the typed buffer
2256 @var{indices} and the vertex attribute data within @var{attributes}.
2258 @var{attributes} is an alist mapping shader attribute indices to typed
2259 buffers containing vertex data:
2262 `((1 . ,typed-buffer-a)
2263 (2 . ,typed-buffer-b)
2267 By default, the vertex array is interpreted as containing a series of
2268 triangles. If another primtive type is desired, the @var{mode}
2269 keyword argument may be overridden. The following values are
2275 @item @code{line-loop}
2276 @item @code{line-strip}
2277 @item @code{triangles}
2278 @item @code{triangle-strip}
2279 @item @code{triangle-fan}
2284 @defvar null-vertex-array
2285 Represents the absence of a vertex array.
2288 @deffn {Procedure} vertex-array? @var{obj}
2289 Return @code{#t} if @var{obj} is a vertex array.
2292 @deffn {Procedure} vertex-array-indices @var{vertex-array}
2293 Return the typed buffer containing index data for @var{vertex-array}.
2296 @deffn {Procedure} vertex-array-attributes @var{vertex-array}
2297 Return the attribute index -> typed buffer mapping of vertex attribute
2298 data for @var{vertex-array}.
2301 @deffn {Procedure} vertex-array-mode @var{vertex-array}
2302 Return the primitive rendering mode for @var{vertex-array}.
2308 Shaders are programs that the GPU can evaluate that allow the
2309 programmer to completely customized the final output of a GPU draw
2310 call. The @code{(chickadee render shader)} module provides an API for
2311 building custom shaders.
2313 Shaders are written in the OpenGL Shading Language, or GLSL for short.
2314 Chickadee aspires to provide a domain specific language for writing
2315 shaders in Scheme, but we are not there yet.
2317 Shader programs consist of two components: A vertex shader and a
2318 fragment shader. A vertex shader receives vertex data (position
2319 coordinates, texture coordinates, normals, etc.) and transforms them
2320 as desired, whereas a fragment shader controls the color of each
2323 Sample vertex shader:
2336 gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
2341 Sample fragment shader:
2348 uniform sampler2D colorTexture;
2351 gl_FragColor = texture2D(colorTexture, fragTex);
2356 This manual will not cover GLSL features and syntax as there is lots
2357 of information already available about this topic.
2359 One way to think about rendering with shaders, and the metaphor
2360 Chickadee uses, is to think about it as a function call: The shader is
2361 a function, and it is applied to some ``attributes'' (positional
2362 arguments), and some ``uniforms'' (keyword arguments).
2365 (define my-shader (load-shader "vert.glsl" "frag.glsl"))
2366 (define vertices (make-vertex-array ...))
2367 (gpu-apply my-shader vertices #:color red)
2370 @xref{Rendering Engine} for more details about the @code{gpu-apply}
2373 Shaders are incredibly powerful tools, and there's more information
2374 about them than we could ever fit into this manual, so we highly
2375 recommend searching the web for more information and examples. What
2376 we can say, though, is how to use our API:
2378 @deffn {Procedure} strings->shader @var{vertex-source} @var{fragment-source}
2379 Compile @var{vertex-source}, the GLSL code for the vertex shader, and
2380 @var{fragment-source}, the GLSL code for the fragment shader, into a
2384 @deffn {Procedure} load-shader @var{vertex-source-file} @
2385 @var{fragment-source-file}
2387 Compile the GLSL source code within @var{vertex-source-file} and
2388 @var{fragment-source-file} into a GPU shader program.
2391 @deffn {Procedure} make-shader @var{vertex-port} @var{fragment-port}
2392 Read GLSL source from @var{vertex-port} and @var{fragment-port} and
2393 compile them into a GPU shader program.
2396 @deffn {Procedure} shader? @var{obj}
2397 Return @code{#t} if @var{obj} is a shader.
2401 Represents the absence shader program.
2404 @deffn {Procedure} shader-uniform @var{shader} @var{name}
2405 Return the metadata for the uniform @var{name} in @var{shader}.
2408 @deffn {Procedure} shader-uniforms @var{shader}
2409 Return a hash table of uniforms for @var{shader}.
2412 @deffn {Procedure} shader-attributes @var{shader}
2413 Return a hash table of attributes for @var{shader}.
2416 @deffn {Procedure} uniform? @var{obj}
2417 Return @code{#t} if @var{obj} is a uniform.
2420 @deffn {Procedure} uniform-name @var{uniform}
2421 Return the variable name of @var{uniform}.
2424 @deffn {Procedure} uniform-type @var{uniform}
2425 Return the data type of @var{uniform}.
2428 @deffn {Procedure} uniform-value @var{uniform}
2429 Return the current value of @var{uniform}.
2432 @deffn {Procedure} uniform-default-value @var{uniform}
2433 Return the default value of @var{uniform}.
2436 @deffn {Procedure} attribute? @var{obj}
2437 Return @code{#t} if @var{obj} is an attribute.
2440 @deffn {Procedure} attribute-name @var{attribute}
2441 Return the variable name of @var{attribute}.
2444 @deffn {Procedure} attribute-location @var{attribute}
2445 Return the binding location of @var{attribute}.
2448 @deffn {Procedure} attribute-type @var{attribute}
2449 Return the data type of @var{attribute}.
2455 Game logic is a web of asynchronous events that are carefully
2456 coordinated to bring the game world to life. In order to make an
2457 enemy follow and attack the player, or move an NPC back and forth in
2458 front of the item shop, or do both at the same time, a scripting
2459 system is a necessity. Chickadee comes with an asynchronous
2460 programming system in the @code{(chickadee scripting)} module.
2461 Lightweight, cooperative threads known as ``scripts'' allow the
2462 programmer to write asynchronous code as if it were synchronous, and
2463 allow many such ``threads'' to run concurrently.
2465 But before we dig deeper into scripts, let's discuss the simple act
2466 of scheduling tasks.
2469 * Agendas:: Scheduling tasks.
2470 * Scripts:: Cooperative multitasking.
2471 * Tweening:: Animations.
2472 * Channels:: Publish data to listeners.
2478 To schedule a task to be performed later, an ``agenda'' is used.
2479 There is a default, global agenda that is ready to be used, or
2480 additional agendas may be created for different purposes. The
2481 following example prints the text ``hello'' when the agenda has
2482 advanced to time unit 10.
2485 (at 10 (display "hello\n"))
2488 Most of the time it is more convenient to schedule tasks relative to
2489 the current time. This is where @code{after} comes in handy:
2492 (after 10 (display "hello\n"))
2495 Time units in the agenda are in no way connected to real time. It's
2496 up to the programmer to decide what agenda time means. A simple and
2497 effective approach is to map each call of the update hook
2498 (@pxref{Kernel}) to 1 unit of agenda time, like so:
2501 (add-hook! update-hook (lambda (dt) (update-agenda 1)))
2504 It is important to call @code{update-agenda} periodically, otherwise
2505 no tasks will ever be run!
2507 In addition to using the global agenda, it is useful to have multiple
2508 agendas for different purposes. For example, the game world can use a
2509 different agenda than the user interface, so that pausing the game is
2510 a simple matter of not updating the world's agenda while continuing to
2511 update the user interface's agenda. The current agenda is dynamically
2512 scoped and can be changed using the @code{with-agenda} special form:
2515 (define game-world-agenda (make-agenda))
2517 (with-agenda game-world-agenda
2518 (at 60 (spawn-goblin))
2519 (at 120 (spawn-goblin))
2520 (at 240 (spawn-goblin-king)))
2523 @deffn {Procedure} make-agenda
2524 Return a new task scheduler.
2527 @deffn {Procedure} agenda? @var{obj}
2528 Return @code{#t} if @var{obj} is an agenda.
2531 @deffn {Procedure} current-agenda
2532 @deffnx {Procedure} current-agenda @var{agenda}
2533 When called with no arguments, return the current agenda. When called
2534 with one argument, set the current agenda to @var{agenda}.
2537 @deffn {Syntax} with-agenda @var{agenda} @var{body} @dots{}
2538 Evaluate @var{body} with the current agenda set to @var{agenda}.
2541 @deffn {Procedure} agenda-time
2542 Return the current agenda time.
2545 @deffn {Procedure} update-agenda @var{dt}
2546 Advance the current agenda by @var{dt}.
2549 @deffn {Procedure} schedule-at @var{time} @var{thunk}
2550 Schedule @var{thunk}, a procedure of zero arguments, to be run at
2554 @deffn {Procedure} schedule-after @var{delay} @var{thunk}
2555 Schedule @var{thunk}, a procedure of zero arguments, to be run after
2559 @deffn {Procedure} schedule-every @var{interval} @var{thunk} [@var{n}]
2560 Schedule @var{thunk}, a procedure of zero arguments, to be run every
2561 @var{interval} amount of time. Repeat this @var{n} times, or
2562 indefinitely if not specified.
2565 @deffn {Syntax} at @var{time} @var{body} @dots{}
2566 Schedule @var{body} to be evaluated at @var{time}.
2569 @deffn {Syntax} after @var{delay} @var{body} @dots{}
2570 Schedule @var{body} to be evaluated after @var{delay}.
2573 @deffn {Syntax} every @var{interval} @var{body} @dots{}
2574 @deffnx {Syntax} every (@var{interval} @var{n}) @var{body} @dots{}
2575 Schedule @var{body} to be evaluated every @var{interval} amount of
2576 time. Repeat this @var{n} times, or indefinitely if not specified.
2582 Now that we can schedule tasks, let's take things to the next level.
2583 It sure would be great if we could make procedures that described a
2584 series of actions that happened over time, especially if we could do
2585 so without contorting our code into a nest of callback procedures.
2586 This is where scripts come in. With scripts we can write code in a
2587 linear way, in a manner that appears to be synchronous, but with the
2588 ability to suspend periodically in order to let other scripts have a
2589 turn and prevent blocking the game loop. Building on top of the
2590 scheduling that agendas provide, here is a script that models a child
2591 trying to get their mother's attention:
2598 (sleep 60))) ; where 60 = 1 second of real time
2601 This code runs in an endless loop, but the @code{sleep} procedure
2602 suspends the script and schedules it to be run later by the agenda.
2603 So, after each iteration of the loop, control is returned back to the
2604 game loop and the program is not stuck spinning in a loop that will
2605 never exit. Pretty neat, eh?
2607 Scripts can suspend to any capable handler, not just the agenda.
2608 The @code{yield} procedure will suspend the current script and pass
2609 its ``continuation'' to a handler procedure. This handler procedure
2610 could do anything. Perhaps the handler stashes the continuation
2611 somewhere where it will be resumed when the user presses a specific
2612 key on the keyboard, or maybe it will be resumed when the player picks
2613 up an item off of the dungeon floor; the sky is the limit.
2615 Sometimes it is necessary to abruptly terminate a script after it has
2616 been started. For example, when an enemy is defeated their AI routine
2617 needs to be shut down. When a script is spawned, a handle to that
2618 script is returned that can be used to cancel it when desired.
2621 (define script (script (while #t (display "hey\n") (sleep 60))))
2623 (cancel-script script)
2626 @deffn {Procedure} spawn-script @var{thunk}
2627 Apply @var{thunk} as a script and return a handle to it.
2630 @deffn {Syntax} script @var{body} @dots{}
2631 Evaluate @var{body} as a script and return a handle to it.
2634 @deffn {Procedure} script? @var{obj}
2635 Return @code{#t} if @var{obj} is a script handle.
2638 @deffn {Procedure} script-cancelled? @var{obj}
2639 Return @code{#t} if @var{obj} has been cancelled.
2642 @deffn {Procedure} script-running? @var{obj}
2643 Return @code{#t} if @var{obj} has not yet terminated or been
2647 @deffn {Procedure} script-complete? @var{obj}
2648 Return @code{#t} if @var{obj} has terminated.
2651 @deffn {Procedure} cancel-script @var{co}
2652 Prevent further execution of the script @var{co}.
2655 @deffn {Procedure} yield @var{handler}
2656 Suspend the current script and pass its continuation to the
2657 procedure @var{handler}.
2660 @deffn {Procedure} sleep @var{duration}
2661 Wait @var{duration} before resuming the current script.
2664 @deffn {Syntax} forever @var{body} @dots{}
2665 Evaluate @var{body} in an endless loop.
2669 @subsection Tweening
2671 Tweening is the process of transitioning something from an initial
2672 state to a final state over a pre-determined period of time. In other
2673 words, tweening is a way to create animation. The @code{tween}
2674 procedure can be used within any script like so:
2679 ;; 0 to 100 in 60 ticks of the agenda.
2680 (tween 60 0 100 (lambda (y) (set! x y))))
2683 @deffn {Procedure} tween @var{duration} @var{start} @var{end} @var{proc} [#:step 1 #:ease @code{smoothstep} #:interpolate @code{lerp}]
2684 Transition a value from @var{start} to @var{end} over @var{duration},
2685 sending each succesive value to @var{proc}. @var{step} controls the
2686 amount of time between each update of the animation.
2688 To control how the animation goes from the initial to final state, an
2689 ``easing'' procedure may be specified. By default, the
2690 @code{smoothstep} easing is used, which is a more pleasing default
2691 than a simplistic linear function. @xref{Easings} for a complete list
2692 of available easing procedures.
2694 The @var{interpolate} procedure computes the values in between
2695 @var{start} and @var{end}. By default, linear interpolation (``lerp''
2700 @subsection Channels
2702 Channels are a tool for communicating amongst different scripts. One
2703 script can write a value to the channel and another can read from it.
2704 Reading or writing to a channel suspends that script until there is
2705 someone on the other end of the line to complete the transaction.
2707 Here's a simplistic example:
2710 (define c (make-channel))
2714 (let ((item (channel-get c)))
2718 (channel-put c 'sword)
2719 (channel-put c 'shield)
2720 (channel-put c 'potion))
2723 @deffn {Procedure} make-channel
2724 Return a new channel
2727 @deffn {Procedure} channel? @var{obj}
2728 Return @code{#t} if @var{obj} is a channel.
2731 @deffn {Procedure} channel-get @var{channel}
2732 Retrieve a value from @var{channel}. The current script suspends
2733 until a value is available.
2736 @deffn {Procedure} channel-put @var{channel} @var{data}
2737 Send @var{data} to @var{channel}. The current script suspends until
2738 another script is available to retrieve the value.
2741 A low-level API also exists for using channels outside of a script via
2742 callback procedures:
2744 @deffn {Procedure} channel-get! @var{channel} @var{proc}
2745 Asynchronously retrieve a value from @var{channel} and call @var{proc}
2749 @deffn {Procedure} channel-put! @var{channel} @var{data} [@var{thunk}]
2750 Asynchronously send @var{data} to @var{channel} and call @var{thunk}
2751 after it has been received.