doc: Document collision grid API.
[chickadee.git] / doc / api.texi
1 @menu
2 * Kernel:: The fundamental components.
3 * Math:: Linear algebra and more.
4 * Graphics:: Eye candy.
5 * Scripting:: Bringing the game world to life.
6 @end menu
8 @node Kernel
9 @section Kernel
11 At the very core of Chickadee, in the @code{(chickadee)} module, lies
12 an event loop. This loop, or ``kernel'', is responsible for ensuring
13 that the game is updated at the desired interval, rendering the
14 current state of the game world, and handling errors if they occur.
15 The kernel implements what is known as a ``fixed timestep'' game loop,
16 meaning that the game simulation will be advanced by a fixed interval
17 of time and will never vary from frame to frame, unlike some other
18 styles of game loops. The appropriately named @code{run-game} and
19 @code{abort-game} procedures are the entry and exit points to the
20 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] @
35 [#:update-hz 60]
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
41 to operate:
43 @itemize
44 @item
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.
48 @item
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.
62 @item
63 @var{time}: Called to get the current time in milliseconds. This
64 procedure is called with no arguments.
65 @item
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.
71 @end itemize
73 @end deffn
75 @deffn {Procedure} abort-game
76 Stop the currently running Chickadee game loop.
77 @end deffn
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 sdl)} module:
83 @code{run-game/sdl}.
85 @deffn {Procedure} run-game/sdl [#:window-title "Chickadee!"] @
86 [#:window-width 640] [#:window-height 480] @
87 [#:window-fullscreen? @code{#f}] [#:update-hz 60] @
88 [#:load] [#:update] [#:draw] [#:quit] @
89 [#:key-press] [#:key-release] [#:text-input] @
90 [#:mouse-press] [#:mouse-release] [#:mouse-move] @
91 [#:controller-add] [#:controller-remove] [#:controller-press] @
92 [#:controller-release] [#:controller-move] [#:error]
94 Run the Chickadee game loop using the SDL engine.
96 A new graphical window will be opened with @var{window-width} x
97 @var{window-height} as its dimensions, @var{window-title} as its
98 title, and in fullscreen mode if @var{window-fullscreen?} is
99 @code{#t}.
101 @itemize
102 @item
103 @var{load}: Called with zero arguments when the game window has opened
104 but before the game loop has started. Can be used to perform
105 initialization that requires an open window and OpenGL context such as
106 loading textures.
108 @item
109 @var{update}: Called @var{update-hz} times per second with one
110 argument: The amount of time to advance the game simulation.
112 @item
113 @var{draw}: Called each time a frame should be rendered with a single
114 argument known as the @code{alpha} value. See the documentation for
115 @code{run-game} for an explanation of this value.
117 @item
118 @var{quit}: Called with zero arguments when the user tries to close
119 the game window. The default behavior is to exit the game.
121 @item
122 @var{key-press}: Called with four arguments when a key is pressed on
123 the keyboard:
125 @enumerate
126 @item
127 @var{key}: The symbolic name of the ``virtual'' key that was pressed.
128 For example: @code{backspace}. It's called a virtual key because the
129 operating system may map a physical keyboard key to another key
130 entirely, such as how the author likes to bind the ``caps lock'' key
131 to mean ``control''.
133 @item
134 @var{scancode}: The symbolic name of the physical key that was
135 pressed.
137 @item
138 @var{modifiers}: A list of the symbolic names of modifier keys that
139 were being held down when the key was pressed. Possible values
140 include @code{ctrl}, @code{alt}, and @code{shift}.
142 @item
143 @var{repeat?}: @code{#t} if this is a repeated press of the same key.
145 @end enumerate
147 @item
148 @var{key-release}: Called with three arguments when a key is released
149 on the keyboard:
151 @enumerate
152 @item
153 @var{key}: The symbolic name of the ``virtual'' key that was released.
155 @item
156 @var{scancode}: The symbolic name of the physical key that was
157 released.
159 @item
160 @var{modifiers}: A list of the symbolic names of modifier keys that
161 were being held down when the key was released.
163 @end enumerate
165 @item
166 @var{text-input}: Called with a single argument, a string of text,
167 when printable text is typed on the keyboard.
169 @item
170 @var{mouse-press}: Called with four arguments when a mouse button is
171 pressed:
172 @enumerate
174 @item
175 @var{button}: The symbolic name of the button that was pressed, such
176 as @code{left}, @code{middle}, or @code{right}.
178 @item
179 @var{clicks}: The number of times the button has been clicked in a row.
181 @item
182 @var{x}: The x coordinate of the mouse cursor.
184 @item
185 @var{y}: The y coordinate of the mouse cursor.
187 @end enumerate
189 @item
190 @var{mouse-release}: Called with three arguments when a mouse button
191 is released:
193 @enumerate
195 @item
196 @var{button}: The symbolic name of the button that was released.
198 @item
199 @var{x}: The x coordinate of the mouse cursor.
201 @item
202 @var{y}: The y coordinate of the mouse cursor.
204 @end enumerate
206 @item
207 @var{mouse-move}: Called with five arguments when the mouse is moved:
209 @enumerate
211 @item
212 @var{x}: The x coordinate of the mouse cursor.
214 @item
215 @var{y}: The y coordinate of the mouse cursor.
217 @item
218 @var{dx}: The amount the mouse has moved along the x axis since the
219 last mouse move event.
221 @item
222 @var{dy}: The amount the mouse has moved along the y axis since the
223 last mouse move event.
225 @item
226 @var{buttons}: A list of the buttons that were pressed down when the
227 mouse was moved.
229 @end enumerate
231 @item
232 @var{controller-add}: Called with a single argument, an SDL game
233 controller object, when a game controller is connected.
235 @item
236 @var{controller-remove}: Called with a single argument, an SDL game
237 controller object, when a game controller is disconnected.
239 @item
240 @var{controller-press}: Called with two arguments when a button on a
241 game controller is pressed:
243 @enumerate
245 @item
246 @var{controller}: The controller that triggered the event.
248 @item
249 @var{button}: The symbolic name of the button that was pressed.
250 Possible buttons are:
252 @itemize
253 @item
254 @code{a}
255 @item
256 @code{b}
257 @item
258 @code{x}
259 @item
260 @code{y}
261 @item
262 @code{back}
263 @item
264 @code{guide}
265 @item
266 @code{start}
267 @item
268 @code{left-stick}
269 @item
270 @code{right-stick}
271 @item
272 @code{left-shoulder}
273 @item
274 @code{right-shoulder}
275 @item
276 @code{dpad-up}
277 @item
278 @code{dpad-down}
279 @item
280 @code{dpad-left}
281 @item
282 @code{dpad-right}
284 @end itemize
286 @end enumerate
288 @item
289 @var{controller-release}: Called with two arguments when a button on a
290 game controller is released:
292 @enumerate
294 @item
295 @var{controller}: The controller that triggered the event.
297 @item
298 @var{button}: The symbolic name of the button that was released.
300 @end enumerate
302 @item
303 @var{controller-move}: Called with three arguments when an analog
304 stick or trigger on a game controller is moved:
306 @enumerate
308 @item
309 @var{controller}: The controller that triggered the event.
311 @item
312 @var{axis}: The symbolic name of the axis that was moved. Possible
313 values are:
315 @itemize
316 @item
317 @code{left-x}
318 @item
319 @code{left-y}
320 @item
321 @code{right-x}
322 @item
323 @code{right-y}
324 @item
325 @code{trigger-left}
326 @item
327 @code{trigger-right}
328 @end itemize
330 @end enumerate
332 @item
333 @var{error}: Called with three arguments when an error occurs:
335 @enumerate
337 @item
338 @var{stack}: The call stack at the point of error.
340 @item
341 @var{key}: The exception key.
343 @item
344 @var{args}: The arguments thrown with the exception.
346 @end enumerate
348 The default behavior is to re-throw the error.
350 @end itemize
352 @end deffn
354 @node Math
355 @section Math
357 Chickadee contains data types and procedures for performing the most
358 common computations in video game simulations such as linear algebra
359 with vectors and matrices and axis-aligned bounding box collision
360 detection.
362 @menu
363 * Basics:: Commonly used, miscellaneous things.
364 * Vectors:: Euclidean vectors.
365 * Rectangles:: Axis-aligned bounding boxes.
366 * Grid:: Spatial partitioning for bounding boxes.
367 * Matrices:: Transformation matrices.
368 * Quaternions:: Rotations about an arbitrary axis.
369 * Easings:: Easing functions for interesting animations.
370 * Bezier Curves:: Cubic Bezier curves and paths in 2D space.
371 @end menu
373 @node Basics
374 @subsection Basics
376 @defvar pi
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.''
381 @end defvar
383 @defvar pi/2
384 Half of @var{pi}.
385 @end defvar
387 @deffn {Procedure} cotan @var{z}
388 Return the cotangent of @var{z}.
389 @end deffn
391 @node Vectors
392 @subsection Vectors
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
399 release.
401 Here's a quick example of adding two vectors:
403 @example
404 (define v (vec2+ (vec2 1 2) (vec2 3 4)))
405 @end example
407 Since vectors are used so frequently, the reader macro @code{#v} is
408 used to cut down on typing:
410 @example
411 (define v (vec2+ #v(1 2) #v(3 4)))
412 @end example
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}).
430 @end deffn
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
435 measured in radians.
436 @end deffn
438 @deffn {Procedure} vec2? @var{obj}
439 Return @code{#t} if @var{obj} is a 2D vector.
440 @end deffn
442 @deffn {Procedure} vec2-x @var{v}
443 Return the X coordinate of the 2D vector @var{v}.
444 @end deffn
446 @deffn {Procedure} vec2-y @var{v}
447 Return the Y coordinate of the 2D vector @var{v}.
448 @end deffn
450 @deffn {Procedure} vec2-copy @var{v}
451 Return a fresh copy of the 2D vector @var{v}.
452 @end deffn
454 @deffn {Procedure} vec2-magnitude @var{v}
455 Return the magnitude of the 2D vector @var{v}.
456 @end deffn
458 @deffn {Procedure} vec2-dot-product @var{v1} @var{v2}
459 Return the dot product of the 2D vectors @var{v1} and @var{v2}.
460 @end deffn
462 @deffn {Procedure} vec2-normalize @var{v}
463 Return the normalized form of the 2D vector @var{v}.
464 @end deffn
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.
469 @end deffn
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.
474 @end deffn
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.
479 @end deffn
481 @deffn {Procedure} set-vec2-x! @var{v} @var{x}
482 Set the X coordinate of the 2D vector @var{v} to @var{x}.
483 @end deffn
485 @deffn {Procedure} set-vec2-y! @var{v} @var{y}
486 Set the Y coordinate of the 2D vector @var{v} to @var{y}.
487 @end deffn
489 @deffn {Procedure} vec2-copy! @var{source} @var{target}
490 Copy the 2D vector @var{source} into the 2D vector @var{target}.
491 @end deffn
493 @deffn {Procedure} vec2-add! @var{v} @var{x}
494 Perform an in-place modification of the 2D vector @var{v} by adding
495 @var{x}, a 2D vector or a scalar.
496 @end deffn
498 @deffn {Procedure} vec2-sub! @var{v} @var{x}
499 Perform an in-place modification of the 2D vector @var{v} by
500 subtracting @var{x}, a 2D vector or a scalar.
501 @end deffn
503 @deffn {Procedure} vec2-mult! @var{v} @var{x}
504 Perform an in-place modification of the 2D vector @var{v} by
505 multiplying it by @var{x}, a 2D vector or a scalar.
506 @end deffn
508 @subsubsection 3D Vectors
510 @deffn {Procedure} vec3 @var{x} @var{y}
511 Return a new 2D vector with coordinates (@var{x}, @var{y}).
512 @end deffn
514 @deffn {Procedure} vec3? @var{obj}
515 Return @code{#t} if @var{obj} is a 3D vector.
516 @end deffn
518 @deffn {Procedure} vec3-x @var{v}
519 Return the X coordinate of the 3D vector @var{v}.
520 @end deffn
522 @deffn {Procedure} vec3-y @var{v}
523 Return the Y coordinate of the 3D vector @var{v}.
524 @end deffn
526 @deffn {Procedure} vec3-z @var{v}
527 Return the Z coordinate of the 3D vector @var{v}.
528 @end deffn
530 @deffn {Procedure} vec3-copy @var{v}
531 Return a fresh copy of the 3D vector @var{v}.
532 @end deffn
534 @deffn {Procedure} vec3-magnitude @var{v}
535 Return the magnitude of the 3D vector @var{v}.
536 @end deffn
538 @deffn {Procedure} vec3-dot-product @var{v1} @var{v2}
539 Return the dot product of the 3D vectors @var{v1} and @var{v2}.
540 @end deffn
542 @deffn {Procedure} vec3-normalize @var{v}
543 Return the normalized form of the 3D vector @var{v}.
544 @end deffn
546 @deffn {Procedure} vec3+ @var{v} @var{x}
547 Add @var{x}, either a 3D vector or a scalar (i.e. a real number), to
548 the 3D vector @var{v} and return a new vector containing the sum.
549 @end deffn
551 @deffn {Procedure} vec3- @var{v} @var{x}
552 Subtract @var{x}, either a 3D vector or a scalar, from the 3D vector
553 @var{v} and return a new vector containing the difference.
554 @end deffn
556 @deffn {Procedure} vec3* @var{v} @var{x}
557 Multiply the 3D vector @var{v} by @var{x}, a 3D vector or a scalar,
558 and return a new vector containing the product.
559 @end deffn
561 @deffn {Procedure} set-vec3-x! @var{v} @var{x}
562 Set the X coordinate of the 3D vector @var{v} to @var{x}.
563 @end deffn
565 @deffn {Procedure} set-vec3-y! @var{v} @var{y}
566 Set the Y coordinate of the 3D vector @var{v} to @var{y}.
567 @end deffn
569 @deffn {Procedure} set-vec3-z! @var{v} @var{z}
570 Set the Z coordinate of the 3D vector @var{v} to @var{z}.
571 @end deffn
573 @deffn {Procedure} vec3-copy! @var{source} @var{target}
574 Copy the 3D vector @var{source} into the 3D vector @var{target}.
575 @end deffn
577 @deffn {Procedure} vec3-add! @var{v} @var{x}
578 Perform an in-place modification of the 3D vector @var{v} by adding
579 @var{x}, a 3D vector or a scalar.
580 @end deffn
582 @deffn {Procedure} vec3-sub! @var{v} @var{x}
583 Perform an in-place modification of the 3D vector @var{v} by
584 subtracting @var{x}, a 3D vector or a scalar.
585 @end deffn
587 @deffn {Procedure} vec3-mult! @var{v} @var{x}
588 Perform an in-place modification of the 3D vector @var{v} by
589 multiplying it by @var{x}, a 3D vector or a scalar.
590 @end deffn
592 @node Rectangles
593 @subsection Rectangles
595 The @code{(chickadee math rect)} module provides an API for
596 manipulating axis-aligned bounding boxes (AABBs). AABBs are often
597 used for collision detection in games. Common use-cases are defining
598 ``hitboxes'' in platformers or using them for the ``broad phase'' of a
599 collision detection algorithm that uses a more complex (and thus
600 slower) method of determining the actual collisions.
602 Like some of the other math modules, there exists a collection of
603 functions that do in-place modification of rectangles for use in
604 performance critical code paths.
606 @deffn {Procedure} make-rect @var{x} @var{y} @var{width} @var{height}
607 Create a new rectangle that is @var{width} by @var{height} in size and
608 whose bottom-left corner is located at (@var{x}, @var{y}).
609 @end deffn
611 @deffn {Procedure} rect? @var{obj}
612 Return @code{#t} if @var{obj} is a rectangle.
613 @end deffn
615 @deffn {Procedure} rect-within? @var{rect1} @var{rect2}
616 Return @code{#t} if @var{rect2} is completely within @var{rect1}.
617 @end deffn
619 @deffn {Procedure} rect-intersects? @var{rect1} @var{rect2}
620 Return @code{#t} if @var{rect2} overlaps @var{rect1}.
621 @end deffn
623 @deffn {Procedure} rect-contains? @var{rect} @var{x} @var{y}
624 Return @code{#t} if the coordinates (@var{x}, @var{y}) are within
625 @var{rect}.
626 @end deffn
628 @deffn {Procedure} rect-contains-vec2? @var{rect} @var{v}
629 Return @code{#t} if the 2D vector @var{v} is within the bounds of
630 @var{rect}.
631 @end deffn
633 @deffn {Procedure} rect-x @var{rect}
634 Return the X coordinate of the lower-left corner of @var{rect}.
635 @end deffn
637 @deffn {Procedure} rect-y @var{rect}
638 Return the Y coordinate of the lower-left corner of @var{rect}.
639 @end deffn
641 @deffn {Procedure} rect-left @var{rect}
642 Return the left-most X coordinate of @var{rect}.
643 @end deffn
645 @deffn {Procedure} rect-right @var{rect}
646 Return the right-most X coordinate of @var{rect}.
647 @end deffn
649 @deffn {Procedure} rect-bottom @var{rect}
650 Return the bottom-most Y coordinate of @var{rect}.
651 @end deffn
653 @deffn {Procedure} rect-top @var{rect}
654 Return the top-most Y coordinate of @var{rect}.
655 @end deffn
657 @deffn {Procedure} rect-center-x @var{rect}
658 Return the X coordinate of the center of @var{rect}.
659 @end deffn
661 @deffn {Procedure} rect-center-y @var{rect}
662 Return the Y coordinate of the center of @var{rect}.
663 @end deffn
665 @deffn {Procedure} rect-width @var{rect}
666 Return the width of @var{rect}.
667 @end deffn
669 @deffn {Procedure} rect-height @var{rect}
670 Return the height of @var{rect}.
671 @end deffn
673 @deffn {Procedure} rect-area @var{rect}
674 Return the surface area covered by @var{rect}.
675 @end deffn
677 @deffn {Procedure} rect-clamp-x @var{rect} @var{x}
678 Restrict @var{x} to the portion of the X axis covered by @var{rect}.
679 @end deffn
681 @deffn {Procedure} rect-clamp-y @var{rect} @var{y}
682 Restrict @var{y} to the portion of the Y axis covered by @var{rect}.
683 @end deffn
685 @deffn {Procedure} rect-clamp @var{rect1} @var{rect2}
686 Return a new rect that adjusts the location of @var{rect1} so that it
687 is completely within @var{rect2}. An exception is thrown in the case
688 that @var{rect1} cannot fit completely within @var{rect2}.
689 @end deffn
691 @deffn {Procedure} rect-move @var{rect} @var{x} @var{y}
692 Return a new rectangle based on @var{rect} but moved to the
693 coordinates (@var{x}, @var{y}).
694 @end deffn
696 @deffn {Procedure} rect-move-vec2 @var{rect} @var{v}
697 Return a new rectangle based on @var{rect} but moved to the
698 coordinates in the 2D vector @var{v}.
699 @end deffn
701 @deffn {Procedure} rect-move-by @var{rect} @var{x} @var{y}
702 Return a new rectangle based on @var{rect} but moved by (@var{x},
703 @var{y}) units relative to its current location.
704 @end deffn
706 @deffn {Procedure} rect-move-by-vec2 @var{rect} @var{v}
707 Return a new rectangle based on @var{rect} but moved by the 2D vector
708 @var{v} relative to its current location.
709 @end deffn
711 @deffn {Procedure} rect-inflate @var{rect} @var{width} @var{height}
712 Return a new rectangle based on @var{rect}, but expanded by
713 @var{width} units on the X axis and @var{height} units on the Y axis,
714 while keeping the rectangle centered on the same point.
715 @end deffn
717 @deffn {Procedure} rect-union @var{rect1} @var{rect2}
718 Return a new rectangle that completely covers the area of @var{rect1}
719 and @var{rect2}.
720 @end deffn
722 @deffn {Procedure} rect-clip @var{rect1} @var{rect2}
723 Return a new rectangle that is the overlapping region of @var{rect1}
724 and @var{rect2}. If the two rectangles do not overlap, a rectangle of
725 0 width and 0 height is returned.
726 @end deffn
728 @deffn {Procedure} set-rect-x! @var{rect} @var{x}
729 Set the left X coordinate of @var{rect} to @var{x}.
730 @end deffn
732 @deffn {Procedure} set-rect-y! @var{rect} @var{y}
733 Set the bottom Y coordinate of @var{rect} to @var{y}.
734 @end deffn
736 @deffn {Procedure} set-rect-width! @var{rect} @var{width}
737 Set the width of @var{rect} to @var{width}.
738 @end deffn
740 @deffn {Procedure} set-rect-height! @var{rect} @var{height}
741 Set the height of @var{rect} to @var{height}.
742 @end deffn
744 @deffn {Procedure} rect-move! @var{rect} @var{x} @var{y}
745 Move @var{rect} to (@var{x}, @var{y}) in-place.
746 @end deffn
748 @deffn {Procedure} rect-move-vec2! @var{rect} @var{v}
749 Move @var{rect} to the 2D vector @var{v} in-place.
750 @end deffn
752 @deffn {Procedure} rect-move-by! @var{rect} @var{x} @var{y}
753 Move @var{rect} by (@var{x}, @var{y}) in-place.
754 @end deffn
756 @deffn {Procedure} rect-move-by-vec2! @var{rect} @var{v}
757 Move @var{rect} by the 2D vector @var{v} in-place.
758 @end deffn
760 @deffn {Procedure} rect-inflate! @var{rect} @var{width} @var{height}
761 Expand @var{rect} by @var{width} and @var{height} in-place.
762 @end deffn
764 @deffn {Procedure} rect-union! @var{rect1} @var{rect2}
765 Modify @var{rect1} in-place to completely cover the area of both
766 @var{rect1} and @var{rect2}.
767 @end deffn
769 @deffn {Procedure} rect-clip! @var{rect1} @var{rect2}
770 Modify @var{rect1} in-place to be the overlapping region of
771 @var{rect1} and @var{rect2}.
772 @end deffn
774 @deffn {Procedure} rect-clamp! @var{rect1} @var{rect2}
775 Adjust the location of @var{rect1} in-place so that its bounds are
776 completely within @var{rect2}. An exception is thrown in the case
777 that @var{rect1} cannot fit completely within @var{rect2}.
778 @end deffn
780 @deffn {Procedure} vec2-clamp-to-rect! @var{v} @var{rect}
781 Restrict the coordinates of the 2D vector @var{v} so that they are
782 within the bounds of @var{rect}. @var{v} is modified in-place.
783 @end deffn
785 @node Grid
786 @subsection Grid
788 The @code{(chickadee math grid)} module provides a simple spatial
789 partitioning system for axis-aligned bounding boxes
790 (@pxref{Rectangles}) in 2D space. The grid divides the world into
791 tiles and keeps track of which rectangles occupy which tiles. When
792 there are lots of moving objects in the game world that need collision
793 detection, the grid greatly speeds up the process. Instead of
794 checking collisions of each object against every other object (an
795 O(n^2) operation), the grid quickly narrows down which objects could
796 possibly be colliding and only performs collision testing against a
797 small set of objects.
799 In addition to checking for collisions, the grid also handles the
800 resolution of collisions. Exactly how each collision is resolved is
801 user-defined. A player bumping into a wall may slide against it. An
802 enemy colliding with a projectile shot by the player may get pushed
803 back in the opposite direction. Two players colliding may not need
804 resolution at all and will just pass through each other. The way this
805 works is that each time an object (A) is moved within the grid, the
806 grid looks for an object (B) that may possibly be colliding with A. A
807 user-defined procedure known as a ``filter'' is then called with both
808 A and B. If the filter returns @code{#f}, it means that even if A and
809 B are colliding, no collision resolution is needed. In this case the
810 grid won't waste time checking if they really do collide because it
811 doesn't matter. If A and B are collidable, then the filter returns a
812 procedure that implements the resolution technique. The grid will
813 then perform a collision test. If A and B are colliding, the resolver
814 procedure is called. It's the resolvers job to adjust the objects
815 such that they are no longer colliding. The grid module comes with a
816 very simple resolution procedure, @code{slide}, that adjusts object A
817 by the smallest amount so that it no longer overlaps with B. By using
818 this filtering technique, a game can resolve collisions between
819 different objects in different ways.
821 @deffn {Procedure} make-grid [@var{cell-size} 64]
822 Return a new grid partitioned into @var{cell-size} tiles.
823 @end deffn
825 @deffn {Procedure} grid? @var{obj}
826 Return @code{#t} if @var{obj} is a grid.
827 @end deffn
829 @deffn {Procedure} cell? @var{obj}
830 Return @code{#t} if @var{obj} is a grid cell.
831 @end deffn
833 @deffn {Procedure} cell-count @var{cell}
834 Return the number of items in @var{cell}.
835 @end deffn
837 @deffn {Procedure} grid-cell-size @var{grid}
838 Return the cell size of @var{grid}.
839 @end deffn
841 @deffn {Procedure} grid-cell-count @var{grid}
842 Return the number of cells currently in @var{grid}.
843 @end deffn
845 @deffn {Procedure} grid-item-count @var{grid}
846 Return the number of items in @var{grid}.
847 @end deffn
849 @deffn {Procedure} grid-add @var{grid} @var{item} @var{x} @var{y} @
850 @var{width} @var{height}
852 Add @var{item} to @var{grid} represented by the axis-aligned bounding
853 box whose lower-left corner is at (@var{x}, @var{y}) and is
854 @var{width} x @var{height} in size.
855 @end deffn
857 @deffn {Procedure} grid-remove @var{grid} @var{item}
858 Return @var{item} from @var{grid}.
859 @end deffn
861 @deffn {Procedure} grid-clear @var{grid}
862 Remove all items from @var{grid}.
863 @end deffn
865 @deffn {Procedure} grid-move @var{grid} @var{item} @var{position} @var{filter}
866 Attempt to move @var{item} in @var{grid} to @var{position} (a 2D
867 vector) and check for collisions. For each collision, @var{filter}
868 will be called with two arguments: @var{item} and the item it collided
869 with. If a collision occurs, @var{position} may be modified to
870 resolve the colliding objects.
871 @end deffn
873 @deffn {Procedure} for-each-cell @var{proc} @var{grid} [@var{rect}]
874 Call @var{proc} with each cell in @var{grid} that intersects
875 @var{rect}, or every cell if @var{rect} is @code{#f}.
876 @end deffn
878 @deffn {Procedure} for-each-item @var{proc} @var{grid}
879 Call @var{proc} for each item in @var{grid}.
880 @end deffn
882 @deffn {Procedure} slide @var{item} @var{item-rect} @
883 @var{other} @var{other-rect} @var{goal}
885 Resolve the collision that occurs between @var{item} and @var{other}
886 when moving @var{item-rect} to @var{goal} by sliding @var{item-rect}
887 the minimum amount needed to make it no longer overlap
888 @var{other-rect}.
889 @end deffn
891 @node Matrices
892 @subsection Matrices
894 The @code{(chickadee math matrix)} module provides an interface for
895 working with the most common type of matrices in game development: 4x4
896 transformation matrices.
898 @subsubsection Another Note About Performance
900 Much like the vector API, the matrix API is commonly used in
901 performance critical code paths. In order to reduce the amount of
902 garbage generated and improve matrix multiplication performance, there
903 are many procedures that perform in-place modifications of matrix
904 objects.
906 @subsubsection Matrix Operations
908 @deffn {Procedure} make-matrix4 @var{aa} @var{ab} @var{ac} @var{ad} @
909 @var{ba} @var{bb} @var{bc} @var{bd} @
910 @var{ca} @var{cb} @var{cc} @var{cd} @
911 @var{da} @var{db} @var{dc} @var{dd}
913 Return a new 4x4 matrix initialized with the given 16 values in
914 column-major format.
915 @end deffn
917 @deffn {Procedure} make-null-matrix4
918 Return a new 4x4 matrix with all values initialized to 0.
919 @end deffn
921 @deffn {Procedure} make-identity-matrix4
922 Return a new 4x4 identity matrix. Any matrix multiplied by the
923 identity matrix yields the original matrix. This procedure is
924 equivalent to the following code:
926 @example
927 (make-matrix4 1 0 0 0
928 0 1 0 0
929 0 0 1 0
930 0 0 0 1)
931 @end example
933 @end deffn
935 @deffn {Procedure} matrix4? @var{obj}
936 Return @code{#t} if @var{obj} is a 4x4 matrix.
937 @end deffn
939 @deffn {Procedure} matrix4* . @var{matrices}
940 Return a new 4x4 matrix containing the product of multiplying all of
941 the given @var{matrices}.
943 Note: Remember that matrix multiplication is @strong{not} commutative!
944 @end deffn
946 @deffn {Procedure} orthographic-projection @var{left} @var{right} @
947 @var{top} @var{bottom} @
948 @var{near} @var{far}
950 Return a new 4x4 matrix that represents an orthographic (2D)
951 projection for the horizontal clipping plane @var{top} and
952 @var{bottom}, the vertical clipping plane @var{top} and @var{bottom},
953 and the depth clipping plane @var{near} and @var{far}.
954 @end deffn
956 @deffn {Procedure} perspective-projection @var{fov} @
957 @var{aspect-ratio} @
958 @var{near} @var{far}
960 Return a new 4x4 matrix that represents a perspective (3D) projection
961 with a field of vision of @var{fov} radians, an aspect ratio of
962 @var{aspect-ratio}, and a depth clipping plane defined by @var{near}
963 and @var{far}.
964 @end deffn
966 @deffn {Procedure} matrix4-translate @var{x}
967 Return a new 4x4 matrix that represents a translation by @var{x}, a 2D
968 vector, a 3D vector, or a rectangle (in which case the bottom-left
969 corner of the rectangle is used).
970 @end deffn
972 @deffn {Procedure} matrix4-scale @var{s}
973 Return a new 4x4 matrix that represents a scaling along the X, Y, and
974 Z axes by the scaling factor @var{s}, a real number.
975 @end deffn
977 @deffn {Procedure} matrix4-rotate @var{q}
978 Return a new 4x4 matrix that represents a rotation about an arbitrary
979 axis defined by the quaternion @var{q}.
980 @end deffn
982 @deffn {Procedure} matrix4-rotate-z @var{theta}
983 Return a new 4x4 matrix that represents a rotation about the Z axis by
984 @var{theta} radians.
985 @end deffn
987 @deffn {Procedure} matrix4-identity! @var{matrix}
988 Modify @var{matrix} in-place to contain the identity matrix.
989 @end deffn
991 @deffn {Procedure} matrix4-mult! @var{dest} @var{a} @var{b}
992 Multiply the 4x4 matrix @var{a} by the 4x4 matrix @var{b} and store
993 the result in the 4x4 matrix @var{dest}.
994 @end deffn
996 @deffn {Procedure} matrix4-translate! @var{matrix} @var{x}
997 Modify @var{matrix} in-place to contain a translation by @var{x}, a 2D
998 vector, a 3D vector, or a rectangle (in which case the bottom-left
999 corner of the rectangle is used).
1000 @end deffn
1002 @deffn {Procedure} matrix4-scale! @var{matrix} @var{s}
1003 Modify @var{matrix} in-place to contain a scaling along the X, Y, and
1004 Z axes by the scaling factor @var{s}, a real number.
1005 @end deffn
1007 @deffn {Procedure} matrix4-rotate! @var{matrix} @var{q}
1008 Modify @var{matrix} in-place to contain a rotation about an arbitrary
1009 axis defined by the quaternion @var{q}.
1010 @end deffn
1012 @deffn {Procedure} matrix4-rotate-z! @var{matrix} @var{theta}
1013 Modify @var{matrix} in-place to contain a rotation about the Z axis by
1014 @var{theta} radians.
1015 @end deffn
1017 @deffn {Procedure} matrix4-2d-transform! @var{matrix} [#:origin] @
1018 [#:position] [#:rotation] @
1019 [#:scale] [#:skew]
1021 Modify @var{matrix} in-place to contain the transformation described
1022 by @var{position}, a 2D vector or rectangle, @var{rotation}, a scalar
1023 representing a rotation about the Z axis, @var{scale}, a 2D vector,
1024 and @var{skew}, a 2D vector. The transformation happens with respect
1025 to @var{origin}, a 2D vector. If an argument is not provided, that
1026 particular transformation will not be included in the result.
1027 @end deffn
1029 @deffn {Procedure} transform! @var{matrix} @var{v}
1030 Modify the 2D vector @var{v} in-place by multiplying it by the 4x4
1031 matrix @var{matrix}.
1032 @end deffn
1034 @node Quaternions
1035 @subsection Quaternions
1037 In game development, the quaternion is most often used to represent
1038 rotations. Why not use a matrix for that, you may ask. Unlike
1039 matrices, quaternions can be interpolated (animated) and produce a
1040 meaningful result. When interpolating two quaternions, there is a
1041 smooth transition from one rotation to another, whereas interpolating
1042 two matrices would yield garbage.
1044 @deffn {Procedure} quaternion @var{x} @var{y} @var{z} @var{w}
1045 Return a new quaternion with values @var{x}, @var{y}, @var{z}, and
1046 @var{w}.
1047 @end deffn
1049 @deffn {Procedure} quaternion? @var{obj}
1050 Return @code{#t} if @var{obj} is a quaternion.
1051 @end deffn
1053 @deffn {Procedure} quaternion-w @var{q}
1054 Return the W component of the quaternion @var{q}.
1055 @end deffn
1057 @deffn {Procedure} quaternion-x @var{q}
1058 Return the X component of the quaternion @var{q}.
1059 @end deffn
1061 @deffn {Procedure} quaternion-y @var{q}
1062 Return the Y component of the quaternion @var{q}.
1063 @end deffn
1065 @deffn {Procedure} quaternion-z @var{q}
1066 Return the Z component of the quaternion @var{q}.
1067 @end deffn
1069 @deffn {Procedure} make-identity-quaternion
1070 Return the identity quaternion.
1071 @end deffn
1073 @node Easings
1074 @subsection Easings
1076 @deffn {Procedure} linear @var{t}
1077 @end deffn
1079 @deffn {Procedure} smoothstep @var{t}
1080 @end deffn
1082 @deffn {Procedure} ease-in-quad @var{t}
1083 @end deffn
1085 @deffn {Procedure} ease-out-quad @var{t}
1086 @end deffn
1088 @deffn {Procedure} ease-in-out-quad @var{t}
1089 @end deffn
1091 @deffn {Procedure} ease-in-cubic @var{t}
1092 @end deffn
1094 @deffn {Procedure} ease-out-cubic @var{t}
1095 @end deffn
1097 @deffn {Procedure} ease-in-out-cubic @var{t}
1098 @end deffn
1100 @deffn {Procedure} ease-in-quart @var{t}
1101 @end deffn
1103 @deffn {Procedure} ease-out-quart @var{t}
1104 @end deffn
1106 @deffn {Procedure} ease-in-out-quart @var{t}
1107 @end deffn
1109 @deffn {Procedure} ease-in-quint @var{t}
1110 @end deffn
1112 @deffn {Procedure} ease-out-quint @var{t}
1113 @end deffn
1115 @deffn {Procedure} ease-in-out-quint @var{t}
1116 @end deffn
1118 @deffn {Procedure} ease-in-sine @var{t}
1119 @end deffn
1121 @deffn {Procedure} ease-out-sine @var{t}
1122 @end deffn
1124 @deffn {Procedure} ease-in-out-sine @var{t}
1125 @end deffn
1127 @node Bezier Curves
1128 @subsection Bezier Curves
1130 The @code{(chickadee math bezier)} module provides an API for
1131 describing cubic Bezier curves in 2D space. These curves are notably
1132 used in font description, vector graphics programs, and when it comes
1133 to games: path building. With Bezier curves, it's somewhat easy to
1134 create a smooth looking path for an enemy to move along, for example.
1135 Bezier curves become particularly interesting when they are chained
1136 together to form a Bezier ``path'', where the end point of one curve
1137 becomes the starting point of the next.
1139 Currently, the rendering of Bezier curves is rather crude and provided
1140 mostly for visualizing and debugging curves that would be unseen in
1141 the final game. See @xref{Lines and Shapes} for more information.
1143 @deffn {Procedure} make-bezier-curve @var{p0} @var{p1} @var{p2} @var{p3}
1144 Return a new Bezier curve object whose starting point is @var{p0},
1145 ending point is @var{p3}, and control points are @var{p1} and
1146 @var{p2}. All points are 2D vectors.
1147 @end deffn
1149 @deffn {Procedure} bezier-curve? @var{obj}
1150 Return @code{#t} if @var{obj} is a Bezier curve.
1151 @end deffn
1153 @deffn {Procedure} bezier-curve-p0 @var{bezier}
1154 Return the starting point of @var{bezier}.
1155 @end deffn
1157 @deffn {Procedure} bezier-curve-p1 @var{bezier}
1158 Return the first control point of @var{bezier}.
1159 @end deffn
1161 @deffn {Procedure} bezier-curve-p2 @var{bezier}
1162 Return the second control point of @var{bezier}.
1163 @end deffn
1165 @deffn {Procedure} bezier-curve-p3 @var{bezier}
1166 Return the end point of @var{bezier}.
1167 @end deffn
1169 @deffn {Procedure} bezier-path . @var{control-points}
1170 Return a list of connected bezier curves defined by
1171 @var{control-points}. The first curve is defined by the first 4
1172 arguments and every additional curve thereafter requires 3 additional
1173 arguments.
1174 @end deffn
1176 @deffn {Procedure} bezier-curve-point-at @var{bezier} @var{t}
1177 Return the coordinates for @var{bezier} at @var{t} (a value in the
1178 range [0, 1] representing how far from the start of the curve to
1179 check) as a 2D vector.
1180 @end deffn
1182 @deffn {Procedure} bezier-curve-point-at! @var{dest} @var{bezier} @var{t}
1183 Modify the 2D vector @var{dest} in-place to contain the coordinates
1184 for @var{bezier} at @var{t}.
1185 @end deffn
1187 @node Graphics
1188 @section Graphics
1190 Chickadee aims to make hardware-accelerated graphics rendering as
1191 simple and efficient as possible by providing high-level APIs that
1192 interact with the low-level OpenGL API under the hood. Anyone that
1193 has worked with OpenGL directly knows that it has a steep learning
1194 curve and a lot of effort is needed to render even a single triangle.
1195 The Chickadee rendering engine attempts to make it easy to do common
1196 tasks like rendering a sprite while also providing all of the building
1197 blocks to implement additional rendering techniques.
1199 @menu
1200 * Rendering Engine:: Rendering state management.
1201 * Textures:: 2D images.
1202 * Sprites:: Draw 2D images.
1203 * Tile Maps:: Draw 2D tile maps.
1204 * Lines and Shapes:: Draw line segments and polygons.
1205 * Fonts:: Drawing text.
1206 * Blending and Depth Testing:: Control how pixels are combined.
1207 * Vertex Arrays:: Create 2D/3D models.
1208 * Shaders:: Create custom GPU programs.
1209 * Framebuffers:: Render to texture.
1210 * Viewports:: Restrict rendering to
1211 @end menu
1213 @node Rendering Engine
1214 @subsection Rendering Engine
1216 Chickadee defines rendering using a metaphor familiar to Scheme
1217 programmers: procedure application. A shader (@pxref{Shaders}) is
1218 like a procedure for the GPU to apply. Shaders are passed arguments:
1219 A vertex array containing the geometry to render (@pxref{Vertex
1220 Arrays}) and zero or more keyword arguments that the shader
1221 understands. Similar to how Scheme has @code{apply} for calling
1222 procedures, Chickadee provides @code{gpu-apply} for calling shaders.
1224 Additionally, there is some dynamic state that effects how
1225 @code{gpu-apply} will behave. Things like the current viewport,
1226 framebuffer, and blend mode are stored as dynamic state because it
1227 would be tedious to have to have to specify them each time
1228 @code{gpu-apply} is called.
1230 The following procedures and syntax can be found in the
1231 @code{(chickadee render)} module.
1233 @deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
1234 [#:uniform-key @var{uniform-value} ...]
1235 @deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
1236 @var{count} [#:uniform-key @var{uniform-value} ...]
1238 Render @var{vertex-array} using @var{shader} with the uniform values
1239 specified in the following keyword arguments.
1241 While @code{gpu-apply} will draw every vertex in @var{vertex-array},
1242 @code{gpu-apply*} will only draw @var{count} vertices.
1244 @end deffn
1246 @deffn {Procedure} current-viewport
1247 Return the currently bound viewport (@pxref{Viewports}).
1248 @end deffn
1250 @deffn {Procedure} current-framebuffer
1251 Return the currently bound framebuffer (@pxref{Framebuffers}).
1252 @end deffn
1254 @deffn {Procedure} current-blend-mode
1255 Return the currently bound blend mode (@pxref{Blending and Depth
1256 Testing}).
1257 @end deffn
1259 @deffn {Procedure} current-depth-test
1260 Return @code{#t} if depth testing is currently enabled (@pxref{Blending and Depth Testing}).
1261 @end deffn
1263 @deffn {Procedure} current-texture
1264 Return the currently bound texture (@pxref{Textures}).
1265 @end deffn
1267 @deffn {Procedure} current-projection
1268 Return the currently bound projection matrix (@pxref{Matrices}).
1269 @end deffn
1271 @deffn {Syntax} with-viewport @var{viewport} @var{body} ...
1272 Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
1273 @end deffn
1275 @deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
1276 Evaluate @var{body} with the current framebuffer bound to
1277 @var{framebuffer} (@pxref{Framebuffers}).
1278 @end deffn
1280 @deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
1281 Evaluate @var{body} with the current blend mode bound to
1282 @var{blend-mode} (@pxref{Blending and Depth Testing}).
1283 @end deffn
1285 @deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
1286 Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
1287 is @code{#f}, or enabled otherwise (@pxref{Blending and Depth
1288 Testing}).
1289 @end deffn
1291 @deffn {Syntax} with-texture @var{texture} @var{body} ...
1292 Evaluate @var{body} with the current texture bound to @var{texture}
1293 (@pxref{Textures}).
1294 @end deffn
1296 @deffn {Syntax} with-projection @var{projection} @var{body} ...
1297 Evaluate @var{body} with the current projection matrix bound to
1298 @var{projection} (@pxref{Matrices}).
1299 @end deffn
1301 @node Textures
1302 @subsection Textures
1304 @deffn {Procedure} load-image @var{file} [#:min-filter nearest] @
1305 [#:mag-filter nearest] [#:wrap-s repeat] [#:wrap-t repeat]
1307 Load the image data from @var{file} and return a new texture object.
1309 @var{min-filter} and @var{mag-filter} describe the method that should
1310 be used for minification and magnification when rendering,
1311 respectively. Possible values are @code{nearest} and @code{linear}.
1313 @var{wrap-s} and @var{wrap-t} describe how to interpret texture
1314 coordinates that are greater than @code{1.0}. Possible values are
1315 @code{repeat}, @code{clamp}, @code{clamp-to-border}, and
1316 @code{clamp-to-edge}.
1318 @end deffn
1320 @node Sprites
1321 @subsection Sprites
1323 For those who are new to this game, a sprite is a 2D rectangular
1324 bitmap that is rendered to the screen. For 2D games, sprites are the
1325 most essential graphical abstraction. They are used for drawing maps,
1326 players, NPCs, items, particles, text, etc. In Chickadee, bitmaps are
1327 stored in textures (@pxref{Textures}) and can be used to draw sprites
1328 via the @code{draw-sprite} procedure.
1330 @deffn {Procedure} draw-sprite @var{texture} @var{position} @
1331 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1332 [#:rect] [#:shader]
1334 Draw @var{texture} at @var{position}.
1336 Optionally, other transformations may be applied to the sprite.
1337 @var{rotation} specifies the angle to rotate the sprite, in radians.
1338 @var{scale} specifies the scaling factor as a 2D vector. All
1339 transformations are applied relative to @var{origin}, a 2D vector,
1340 which defaults to the lower-left corner.
1342 Alpha blending is used by default but the blending method can be
1343 changed by specifying @var{blend-mode}.
1345 The area drawn to is as big as the texture, by default. To draw to an
1346 arbitrary section of the screen, specify @var{rect}.
1348 Finally, advanced users may specify @var{shader} to change the way the
1349 sprite is rendered entirely.
1350 @end deffn
1352 It's not uncommon to need to draw hundreds or thousands of sprites
1353 each frame. However, GPUs (graphics processing units) are tricky
1354 beasts that prefer to be sent few, large chunks of data to render
1355 rather than many, small chunks. Using @code{draw-sprite} on its own
1356 will involve at least one GPU call @emph{per sprite}, which will
1357 quickly lead to poor performance. To deal with this, a technique
1358 known as ``sprite batching'' can be used. Instead of drawing each
1359 sprite immediately, the sprite batch will build up a large of buffer
1360 of sprites to draw and defer rendering until the last possible moment.
1361 Batching isn't a panacea, though. Batching only works if the sprites
1362 being drawn share as much in common as possible. Every time you draw
1363 a sprite with a different texture or blend mode, the batch will be
1364 sent off to the GPU. Therefore, batching is most useful if you
1365 minimize such changes. A good strategy for reducing texture changes
1366 is to stuff many bitmaps into a single image file and create a
1367 ``texture atlas'' (@pxref{Textures}) to access the sub-images within.
1369 Taking advantage of sprite batching in Chickadee is easy, just wrap
1370 the code that is calling @code{draw-sprite} a lot in the
1371 @code{with-batched-sprites} form.
1373 @deffn {Syntax} with-batched-sprites @var{body} @dots{}
1374 Use batched rendering for all @code{draw-sprite} calls within
1375 @var{body}.
1376 @end deffn
1378 With a basic sprite abstraction in place, it's possible to build other
1379 abstractions on top of it. One such example is the ``nine patch''. A
1380 nine patch is a sprite that can be rendered at various sizes without
1381 becoming distorted. This is achieved by diving up the sprite into
1382 nine regions:
1384 @itemize
1385 @item
1386 the center, which can be scaled horizontally and vertically
1387 @item
1388 the four corners, which can never be scaled
1389 @item
1390 the left and right sides, which can be scaled vertically
1391 @item
1392 the top and bottom sides, which can be scaled horizontally
1393 @end itemize
1395 The one caveat is that the bitmap regions must be designed in such a
1396 way so that they are not distorted when stretched along the affected
1397 axes. For example, that means that the top and bottom sides could
1398 have varying colored pixels vertically, but not horizontally.
1400 The most common application of this technique is for graphical user
1401 interface widgets like buttons and dialog boxes. By using a nine
1402 patch, they can be rendered at any size without unappealing scaling
1403 artifacts.
1405 @deffn {Procedure} draw-nine-patch @var{texture} @var{rect} @
1406 [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] @
1407 [#:left-margin margin] [#:right-margin margin] @
1408 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1409 [#:shader]
1411 Draw a nine patch sprite. A nine patch sprite renders @var{texture}
1412 as a @var{width} x @var{height} rectangle whose stretchable areas are
1413 defined by the given margin measurements @var{top-margin},
1414 @var{bottom-margin}, @var{left-margin}, and @var{right-margin}. The
1415 @var{margin} argument may be used to configure all four margins at
1416 once.
1418 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1419 the other arguments.
1420 @end deffn
1422 @node Tile Maps
1423 @subsection Tile Maps
1425 A tile map is a scene created by composing lots of small sprites,
1426 called ``tiles'', into a larger image. One program for editing such
1427 maps is called @url{,Tiled}. Chickadee has native
1428 support for loading and rendering Tiled maps in the @code{(chickadee
1429 render tiled)} module.
1431 @deffn {Procedure} load-tile-map @var{file-name}
1432 Load the Tiled formatted map in @var{file-name} and return a new tile
1433 map object.
1434 @end deffn
1436 @deffn {Procedure} draw-tile-map @var{tile-map} [#:layers] [#:region] @
1437 [#:origin] [#:position] [#:scale] [#:rotation]
1439 Draw the layers of @var{tile-map}. By default, all layers are drawn.
1440 To draw a subset of the available layers, pass a list of layer ids
1441 using the @var{layers} keyword argument.
1443 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1444 the other arguments.
1445 @end deffn
1447 @node Lines and Shapes
1448 @subsection Lines and Shapes
1450 Sprites are fun, but sometimes simple, untextured lines and polygons
1451 are desired. That's where the @code{(chickadee render shapes)} module
1452 comes in!
1454 @deffn {Procedure} draw-line @var{start} @var{end} @
1455 [#:thickness 0.5] [#:feather 1.0] [#:cap round] [#:color] @
1456 [#:shader]
1458 Draw a line segment from @var{start} to @var{end}. The line will be
1459 @var{thickness} pixels thick with an antialiased border @var{feather}
1460 pixels wide. The line will be colored @var{color}. @var{cap}
1461 specifies the type of end cap that should be used to terminate the
1462 lines, either @code{none}, @code{butt}, @code{square}, @code{round},
1463 @code{triangle-in}, or @code{triangle-out}. Advanced users may use
1464 the @var{shader} argument to override the built-in line segment
1465 shader.
1466 @end deffn
1468 @deffn {Procedure} draw-bezier-curve @var{bezier} [#:segments 32] @
1469 [#:control-points?] [#:tangents?] @
1470 [#:control-point-size 8] @
1471 [#:control-point-color yellow] @
1472 [#:tangent-color yellow] @
1473 [#:thickness 0.5] [#:feather 1.0] @
1474 [#:matrix]
1476 Draw the curve defined by @var{bezier} using a resolution of N
1477 @var{segments}. When @var{control-points?} is @code{#t}, the control
1478 points are rendered as squares of size @var{control-point-size} pixels
1479 and a color of @var{control-point-color}. When @var{tangents?} is
1480 @code{#t}, the tangent lines from terminal point to control point are
1481 rendered using the color @var{tangent-color}.
1483 All line segments rendered use @code{draw-line}, and thus the
1484 arguments @var{thickness} and @var{feather} have the same effect as in
1485 that procedure.
1487 A custom @var{matrix} may be passed for applications that require more
1488 control over the final output.
1489 @end deffn
1491 @deffn {Procedure} draw-bezier-path @var{path} [#:segments 32] @
1492 [#:control-points?] [#:tangents?] @
1493 [#:control-point-size 8] @
1494 [#:control-point-color yellow] @
1495 [#:tangent-color yellow] @
1496 [#:thickness 0.5] [#:feather 1.0] @
1497 [#:matrix]
1499 Render @var{path}, a list of bezier curves. See the documentation for
1500 @code{draw-bezier-curve} for an explanation of all the keyword
1501 arguments.
1502 @end deffn
1504 @node Fonts
1505 @subsection Fonts
1507 Unlike the traditional TrueType font format that many are accustomed
1508 to, Chickadee loads and renders bitmap fonts in the
1509 @url{,
1510 Angel Code format}. But why use this seemingly obscure format? It's
1511 easy to find TTFs but not easy to find FNTs (the canonical file
1512 extension used for Angel Code fonts) and bitmap fonts don't scale
1513 well. The reason is efficiency.
1515 If all of the glyphs of a font are pre-rendered and packed into an
1516 image file then it becomes possible to use a texture atlas
1517 (@pxref{Textures}) and a sprite batch (@pxref{Sprites}) when
1518 rendering, which is a more efficient way to render fonts than using,
1519 say, @url{, SDL_ttf} or other
1520 solutions that involve using the FreeType library directly.
1522 Now what about scaling? In libraries that use TTF fonts, one must
1523 choose the size that the glyphs will be rasterized at up front. To
1524 use @code{n} sizes of the same font, one must load @code{n} variants
1525 of that font. If the size of the text is dynamic, some kind of
1526 texture scaling algorithm must be used and the text will inevitably
1527 look blurry. At first glance, using bitmap fonts seem to have an even
1528 worse issue. Instead of just loading the same font @code{n} times at
1529 different sizes, one would need to generate @code{n} image files for
1530 each font size needed. This is where the ``signed distance field''
1531 rendering technique comes in. Introduced by
1532 @url{,
1533 Valve} in 2007, signed distance field fonts can be efficiently stored
1534 in a bitmap and be rendered at arbitrary scale factors with good
1535 results.
1537 While Chickadee does not yet offer a tool for converting TTF fonts
1538 into FNT fonts, tools such as
1539 @url{, Hiero} may be used
1540 in the meantime.
1542 The following procedures can be found in the @code{(chickadee render
1543 font)} module.
1545 @deffn {Procedure} load-font @var{file}
1546 Load the Angel Code formatted XML document in @var{file} and return a
1547 new font object.
1548 @end deffn
1550 @deffn {Procedure} font? @var{obj}
1551 Return @code{#t} if @var{obj} is a font object.
1552 @end deffn
1554 @deffn {Procedure} font-face @var{font}
1555 Return the name of @var{font}.
1556 @end deffn
1558 @deffn {Procedure} font-line-height @var{font}
1559 Return the line height of @var{font}.
1560 @end deffn
1562 @deffn {Procedure} font-line-height @var{font}
1563 Return the line height of @var{font}.
1564 @end deffn
1566 @deffn {Procedure} font-bold? @var{font}
1567 Return @code{#t} if @var{font} is a bold font.
1568 @end deffn
1570 @deffn {Procedure} font-italic? @var{font}
1571 Return @code{#t} if @var{font} is an italicized font.
1572 @end deffn
1574 @deffn {Procedure} draw-text @var{font} @var{text} @var{position}
1575 [#:origin] [#:scale] [#:rotation] [#:blend-mode]
1576 [#:start 0] [#:end @code{(string-length text)}]
1578 Draw the string @var{text} with the first character starting at
1579 @var{position} using @var{font}.
1581 @example
1582 (draw-text font "Hello, world!" (vec2 128.0 128.0))
1583 @end example
1585 To render a substring of @var{text}, use the @var{start} and @var{end}
1586 arguments.
1588 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1589 the other arguments.
1590 @end deffn
1592 @node Blending and Depth Testing
1593 @subsection Blending and Depth Testing
1595 @node Vertex Arrays
1596 @subsection Vertex Arrays
1598 @node Shaders
1599 @subsection Shaders
1601 Shaders are programs for the GPU to evaluate. They are written in the
1602 OpenGL Shading Language, or GLSL. Chickadee does not currently
1603 provide a Scheme-like domain specific language for writing shaders.
1604 Since shaders must be written in GLSL and not Scheme, they are
1605 considered an advanced feature.
1607 @node Framebuffers
1608 @subsection Framebuffers
1610 A framebuffer is a chunk of memory that the GPU can render things
1611 onto. By default, the framebuffer that is used for rendering is the
1612 one belonging to the game window, but custom framebuffers can be used
1613 as well. A common use-case for custom framebuffers is applying
1614 post-processing effects: The entire scene is rendered to a
1615 framebuffer, and then the contents of that framebuffer are applied to
1616 a post-processing shader and rendered to the game window. The
1617 post-processing shader could do any number of things: scaling,
1618 antialiasing, motion blur, etc.
1620 @deffn {Procedure} make-framebuffer @var{width} @var{height} [#:min-filter 'linear] [#:mag-filter 'linear] [#:wrap-s 'repeat] [#:wrap-t 'repeat]
1622 Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high.
1624 @var{min-filter} and @var{mag-filter} determine the scaling algorithm
1625 applied to the framebuffer when rendering. By default, linear scaling
1626 is used in both cases. To perform no smoothing at all, use
1627 @code{nearest} for simple nearest neighbor scaling. This is typically
1628 the best choice for pixel art games.
1629 @end deffn
1631 @deffn {Procedure} framebuffer? @var{obj}
1632 Return @code{#t} if @var{obj} is a framebuffer.
1633 @end deffn
1635 @deffn {Procedure} framebuffer-texture @var{fb}
1636 Return the texture backing the framebuffer @var{fb}.
1637 @end deffn
1639 @deffn {Procedure} framebuffer-viewport @var{fb}
1640 Return the default viewport (@pxref{Viewports}) used by the
1641 framebuffer @var{fb}.
1642 @end deffn
1644 @deffn {Procedure} null-framebuffer
1645 The default framebuffer.
1646 @end deffn
1648 @node Viewports
1649 @subsection Viewports
1651 @node Scripting
1652 @section Scripting
1654 Game logic is a web of asynchronous events that are carefully
1655 coordinated to bring the game world to life. In order to make an
1656 enemy follow and attack the player, or move an NPC back and forth in
1657 front of the item shop, or do both at the same time, a scripting
1658 system is a necessity. Chickadee comes with an asynchronous
1659 programming system in the @code{(chickadee scripting)} module.
1660 Lightweight, cooperative threads known as ``scripts'' allow the
1661 programmer to write asynchronous code as if it were synchronous, and
1662 allow many such ``threads'' to run concurrently.
1664 But before we dig deeper into scripts, let's discuss the simple act
1665 of scheduling tasks.
1667 @menu
1668 * Agendas:: Scheduling tasks.
1669 * Scripts:: Cooperative multitasking.
1670 * Tweening:: Animations.
1671 * Channels:: Publish data to listeners.
1672 @end menu
1674 @node Agendas
1675 @subsection Agendas
1677 To schedule a task to be performed later, an ``agenda'' is used.
1678 There is a default, global agenda that is ready to be used, or
1679 additional agendas may be created for different purposes. The
1680 following example prints the text ``hello'' when the agenda has
1681 advanced to time unit 10.
1683 @example
1684 (at 10 (display "hello\n"))
1685 @end example
1687 Most of the time it is more convenient to schedule tasks relative to
1688 the current time. This is where @code{after} comes in handy:
1690 @example
1691 (after 10 (display "hello\n"))
1692 @end example
1694 Time units in the agenda are in no way connected to real time. It's
1695 up to the programmer to decide what agenda time means. A simple and
1696 effective approach is to map each call of the update hook
1697 (@pxref{Kernel}) to 1 unit of agenda time, like so:
1699 @example
1700 (add-hook! update-hook (lambda (dt) (update-agenda 1)))
1701 @end example
1703 It is important to call @code{update-agenda} periodically, otherwise
1704 no tasks will ever be run!
1706 In addition to using the global agenda, it is useful to have multiple
1707 agendas for different purposes. For example, the game world can use a
1708 different agenda than the user interface, so that pausing the game is
1709 a simple matter of not updating the world's agenda while continuing to
1710 update the user interface's agenda. The current agenda is dynamically
1711 scoped and can be changed using the @code{with-agenda} special form:
1713 @example
1714 (define game-world-agenda (make-agenda))
1716 (with-agenda game-world-agenda
1717 (at 60 (spawn-goblin))
1718 (at 120 (spawn-goblin))
1719 (at 240 (spawn-goblin-king)))
1720 @end example
1722 @deffn {Procedure} make-agenda
1723 Return a new task scheduler.
1724 @end deffn
1726 @deffn {Procedure} agenda? @var{obj}
1727 Return @code{#t} if @var{obj} is an agenda.
1728 @end deffn
1730 @deffn {Procedure} current-agenda
1731 @deffnx {Procedure} current-agenda @var{agenda}
1732 When called with no arguments, return the current agenda. When called
1733 with one argument, set the current agenda to @var{agenda}.
1734 @end deffn
1736 @deffn {Syntax} with-agenda @var{agenda} @var{body} @dots{}
1737 Evaluate @var{body} with the current agenda set to @var{agenda}.
1738 @end deffn
1740 @deffn {Procedure} agenda-time
1741 Return the current agenda time.
1742 @end deffn
1744 @deffn {Procedure} update-agenda @var{dt}
1745 Advance the current agenda by @var{dt}.
1746 @end deffn
1748 @deffn {Procedure} schedule-at @var{time} @var{thunk}
1749 Schedule @var{thunk}, a procedure of zero arguments, to be run at
1750 @var{time}.
1751 @end deffn
1753 @deffn {Procedure} schedule-after @var{delay} @var{thunk}
1754 Schedule @var{thunk}, a procedure of zero arguments, to be run after
1755 @var{delay}.
1756 @end deffn
1758 @deffn {Procedure} schedule-every @var{interval} @var{thunk} [@var{n}]
1759 Schedule @var{thunk}, a procedure of zero arguments, to be run every
1760 @var{interval} amount of time. Repeat this @var{n} times, or
1761 indefinitely if not specified.
1762 @end deffn
1764 @deffn {Syntax} at @var{time} @var{body} @dots{}
1765 Schedule @var{body} to be evaluated at @var{time}.
1766 @end deffn
1768 @deffn {Syntax} after @var{delay} @var{body} @dots{}
1769 Schedule @var{body} to be evaluated after @var{delay}.
1770 @end deffn
1772 @deffn {Syntax} every @var{interval} @var{body} @dots{}
1773 @deffnx {Syntax} every (@var{interval} @var{n}) @var{body} @dots{}
1774 Schedule @var{body} to be evaluated every @var{interval} amount of
1775 time. Repeat this @var{n} times, or indefinitely if not specified.
1776 @end deffn
1778 @node Scripts
1779 @subsection Scripts
1781 Now that we can schedule tasks, let's take things to the next level.
1782 It sure would be great if we could make procedures that described a
1783 series of actions that happened over time, especially if we could do
1784 so without contorting our code into a nest of callback procedures.
1785 This is where scripts come in. With scripts we can write code in a
1786 linear way, in a manner that appears to be synchronous, but with the
1787 ability to suspend periodically in order to let other scripts have a
1788 turn and prevent blocking the game loop. Building on top of the
1789 scheduling that agendas provide, here is a script that models a child
1790 trying to get their mother's attention:
1792 @example
1793 (script
1794 (while #t
1795 (display "mom!")
1796 (newline)
1797 (sleep 60))) ; where 60 = 1 second of real time
1798 @end example
1800 This code runs in an endless loop, but the @code{sleep} procedure
1801 suspends the script and schedules it to be run later by the agenda.
1802 So, after each iteration of the loop, control is returned back to the
1803 game loop and the program is not stuck spinning in a loop that will
1804 never exit. Pretty neat, eh?
1806 Scripts can suspend to any capable handler, not just the agenda.
1807 The @code{yield} procedure will suspend the current script and pass
1808 its ``continuation'' to a handler procedure. This handler procedure
1809 could do anything. Perhaps the handler stashes the continuation
1810 somewhere where it will be resumed when the user presses a specific
1811 key on the keyboard, or maybe it will be resumed when the player picks
1812 up an item off of the dungeon floor; the sky is the limit.
1814 Sometimes it is necessary to abruptly terminate a script after it has
1815 been started. For example, when an enemy is defeated their AI routine
1816 needs to be shut down. When a script is spawned, a handle to that
1817 script is returned that can be used to cancel it when desired.
1819 @example
1820 (define script (script (while #t (display "hey\n") (sleep 60))))
1821 ;; sometime later
1822 (cancel-script script)
1823 @end example
1825 @deffn {Procedure} spawn-script @var{thunk}
1826 Apply @var{thunk} as a script and return a handle to it.
1827 @end deffn
1829 @deffn {Syntax} script @var{body} @dots{}
1830 Evaluate @var{body} as a script and return a handle to it.
1831 @end deffn
1833 @deffn {Procedure} script? @var{obj}
1834 Return @code{#t} if @var{obj} is a script handle.
1835 @end deffn
1837 @deffn {Procedure} script-cancelled? @var{obj}
1838 Return @code{#t} if @var{obj} has been cancelled.
1839 @end deffn
1841 @deffn {Procedure} script-running? @var{obj}
1842 Return @code{#t} if @var{obj} has not yet terminated or been
1843 cancelled.
1844 @end deffn
1846 @deffn {Procedure} script-complete? @var{obj}
1847 Return @code{#t} if @var{obj} has terminated.
1848 @end deffn
1850 @deffn {Procedure} cancel-script @var{co}
1851 Prevent further execution of the script @var{co}.
1852 @end deffn
1854 @deffn {Procedure} yield @var{handler}
1855 Suspend the current script and pass its continuation to the
1856 procedure @var{handler}.
1857 @end deffn
1859 @deffn {Procedure} sleep @var{duration}
1860 Wait @var{duration} before resuming the current script.
1861 @end deffn
1863 @deffn {Procedure} channel-get @var{channel}
1864 Wait for a message from @var{channel}.
1865 @end deffn
1867 @deffn {Syntax} forever @var{body} @dots{}
1868 Evaluate @var{body} in an endless loop.
1869 @end deffn
1871 @node Tweening
1872 @subsection Tweening
1874 Tweening is the process of transitioning something from an initial
1875 state to a final state over a pre-determined period of time. In other
1876 words, tweening is a way to create animation. The @code{tween}
1877 procedure can be used within any script like so:
1879 @example
1880 (define x 0)
1881 (script
1882 ;; 0 to 100 in 60 ticks of the agenda.
1883 (tween 60 0 100 (lambda (y) (set! x y))))
1884 @end example
1886 @deffn {Procedure} tween @var{duration} @var{start} @var{end} @var{proc} [#:step 1 #:ease @code{smoothstep} #:interpolate @code{lerp}]
1887 Transition a value from @var{start} to @var{end} over @var{duration},
1888 sending each succesive value to @var{proc}. @var{step} controls the
1889 amount of time between each update of the animation.
1891 To control how the animation goes from the initial to final state, an
1892 ``easing'' procedure may be specified. By default, the
1893 @code{smoothstep} easing is used, which is a more pleasing default
1894 than a simplistic linear function. @xref{Easings} for a complete list
1895 of available easing procedures.
1897 The @var{interpolate} procedure computes the values in between
1898 @var{start} and @var{end}. By default, linear interpolation (``lerp''
1899 for short) is used.
1900 @end deffn
1902 @node Channels
1903 @subsection Channels
1905 Channels are a tool for communicating amongst different scripts. One
1906 script can write a value to the channel and another can read from it.
1907 Reading or writing to a channel suspends that script until there is
1908 someone on the other end of the line to complete the transaction.
1910 Here's a simplistic example:
1912 @example
1913 (define c (make-channel))
1915 (script
1916 (forever
1917 (let ((item (channel-get c)))
1918 (pk 'got item))))
1920 (script
1921 (channel-put c 'sword)
1922 (channel-put c 'shield)
1923 (channel-put c 'potion))
1924 @end example
1926 @deffn {Procedure} make-channel
1927 Return a new channel
1928 @end deffn
1930 @deffn {Procedure} channel? @var{obj}
1931 Return @code{#t} if @var{obj} is a channel.
1932 @end deffn
1934 @deffn {Procedure} channel-get @var{channel}
1935 Retrieve a value from @var{channel}. The current script suspends
1936 until a value is available.
1937 @end deffn
1939 @deffn {Procedure} channel-put @var{channel} @var{data}
1940 Send @var{data} to @var{channel}. The current script suspends until
1941 another script is available to retrieve the value.
1942 @end deffn