doc: Document bezier curve 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 * 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 @end menu
372 @node Basics
373 @subsection Basics
375 @defvar pi
376 An essential constant for all trigonometry. @code{@U{03C0}} is the ratio
377 of a circle's circumferences to its diameter. Since @code{@U{03C0}} is an
378 irrational number, the @var{pi} in Chickadee is a mere floating point
379 approximation that is ``good enough.''
380 @end defvar
382 @defvar pi/2
383 Half of @var{pi}.
384 @end defvar
386 @deffn {Procedure} cotan @var{z}
387 Return the cotangent of @var{z}.
388 @end deffn
390 @node Vectors
391 @subsection Vectors
393 Unlike Scheme's vector data type, which is a sequence of arbitrary
394 Scheme objects, Chickadee's @code{(chickadee math vector)} module
395 provides vectors in the linear algebra sense: Sequences of numbers
396 specialized for particular coordinate spaces. As of now, Chickadee
397 provides 2D and 3D vectors, with 4D vector support coming in a future
398 release.
400 Here's a quick example of adding two vectors:
402 @example
403 (define v (vec2+ (vec2 1 2) (vec2 3 4)))
404 @end example
406 Since vectors are used so frequently, the reader macro @code{#v} is
407 used to cut down on typing:
409 @example
410 (define v (vec2+ #v(1 2) #v(3 4)))
411 @end example
413 @subsubsection A Note About Performance
415 A lot of time has been spent making Chickadee's vector operations
416 perform relatively efficiently in critical code paths where excessive
417 garbage generation will cause major performance issues. The general
418 rule is that procedures ending with @code{!} perform an in-place
419 modification of one of the arguments in order to avoid allocating a
420 new vector. These procedures are also inlined by Guile's compiler in
421 order to take advantage of optimizations relating to floating point
422 math operations. The downside is that since these are not pure
423 functions, they do not compose well and create more verbose code.
425 @subsubsection 2D Vectors
427 @deffn {Procedure} vec2 @var{x} @var{y}
428 Return a new 2D vector with coordinates (@var{x}, @var{y}).
429 @end deffn
431 @deffn {Procedure} vec2/polar @var{r} @var{theta}
432 Return a new 2D vector containing the Cartesian representation of the
433 polar coordinate (@var{r}, @var{theta}). The angle @var{theta} is
434 measured in radians.
435 @end deffn
437 @deffn {Procedure} vec2? @var{obj}
438 Return @code{#t} if @var{obj} is a 2D vector.
439 @end deffn
441 @deffn {Procedure} vec2-x @var{v}
442 Return the X coordinate of the 2D vector @var{v}.
443 @end deffn
445 @deffn {Procedure} vec2-y @var{v}
446 Return the Y coordinate of the 2D vector @var{v}.
447 @end deffn
449 @deffn {Procedure} vec2-copy @var{v}
450 Return a fresh copy of the 2D vector @var{v}.
451 @end deffn
453 @deffn {Procedure} vec2-magnitude @var{v}
454 Return the magnitude of the 2D vector @var{v}.
455 @end deffn
457 @deffn {Procedure} vec2-dot-product @var{v1} @var{v2}
458 Return the dot product of the 2D vectors @var{v1} and @var{v2}.
459 @end deffn
461 @deffn {Procedure} vec2-normalize @var{v}
462 Return the normalized form of the 2D vector @var{v}.
463 @end deffn
465 @deffn {Procedure} vec2+ @var{v} @var{x}
466 Add @var{x}, either a 2D vector or a scalar (i.e. a real number), to
467 the 2D vector @var{v} and return a new vector containing the sum.
468 @end deffn
470 @deffn {Procedure} vec2- @var{v} @var{x}
471 Subtract @var{x}, either a 2D vector or a scalar, from the 2D vector
472 @var{v} and return a new vector containing the difference.
473 @end deffn
475 @deffn {Procedure} vec2* @var{v} @var{x}
476 Multiply the 2D vector @var{v} by @var{x}, a 2D vector or a scalar,
477 and return a new vector containing the product.
478 @end deffn
480 @deffn {Procedure} set-vec2-x! @var{v} @var{x}
481 Set the X coordinate of the 2D vector @var{v} to @var{x}.
482 @end deffn
484 @deffn {Procedure} set-vec2-y! @var{v} @var{y}
485 Set the Y coordinate of the 2D vector @var{v} to @var{y}.
486 @end deffn
488 @deffn {Procedure} vec2-copy! @var{source} @var{target}
489 Copy the 2D vector @var{source} into the 2D vector @var{target}.
490 @end deffn
492 @deffn {Procedure} vec2-add! @var{v} @var{x}
493 Perform an in-place modification of the 2D vector @var{v} by adding
494 @var{x}, a 2D vector or a scalar.
495 @end deffn
497 @deffn {Procedure} vec2-sub! @var{v} @var{x}
498 Perform an in-place modification of the 2D vector @var{v} by
499 subtracting @var{x}, a 2D vector or a scalar.
500 @end deffn
502 @deffn {Procedure} vec2-mult! @var{v} @var{x}
503 Perform an in-place modification of the 2D vector @var{v} by
504 multiplying it by @var{x}, a 2D vector or a scalar.
505 @end deffn
507 @subsubsection 3D Vectors
509 @deffn {Procedure} vec3 @var{x} @var{y}
510 Return a new 2D vector with coordinates (@var{x}, @var{y}).
511 @end deffn
513 @deffn {Procedure} vec3? @var{obj}
514 Return @code{#t} if @var{obj} is a 3D vector.
515 @end deffn
517 @deffn {Procedure} vec3-x @var{v}
518 Return the X coordinate of the 3D vector @var{v}.
519 @end deffn
521 @deffn {Procedure} vec3-y @var{v}
522 Return the Y coordinate of the 3D vector @var{v}.
523 @end deffn
525 @deffn {Procedure} vec3-z @var{v}
526 Return the Z coordinate of the 3D vector @var{v}.
527 @end deffn
529 @deffn {Procedure} vec3-copy @var{v}
530 Return a fresh copy of the 3D vector @var{v}.
531 @end deffn
533 @deffn {Procedure} vec3-magnitude @var{v}
534 Return the magnitude of the 3D vector @var{v}.
535 @end deffn
537 @deffn {Procedure} vec3-dot-product @var{v1} @var{v2}
538 Return the dot product of the 3D vectors @var{v1} and @var{v2}.
539 @end deffn
541 @deffn {Procedure} vec3-normalize @var{v}
542 Return the normalized form of the 3D vector @var{v}.
543 @end deffn
545 @deffn {Procedure} vec3+ @var{v} @var{x}
546 Add @var{x}, either a 3D vector or a scalar (i.e. a real number), to
547 the 3D vector @var{v} and return a new vector containing the sum.
548 @end deffn
550 @deffn {Procedure} vec3- @var{v} @var{x}
551 Subtract @var{x}, either a 3D vector or a scalar, from the 3D vector
552 @var{v} and return a new vector containing the difference.
553 @end deffn
555 @deffn {Procedure} vec3* @var{v} @var{x}
556 Multiply the 3D vector @var{v} by @var{x}, a 3D vector or a scalar,
557 and return a new vector containing the product.
558 @end deffn
560 @deffn {Procedure} set-vec3-x! @var{v} @var{x}
561 Set the X coordinate of the 3D vector @var{v} to @var{x}.
562 @end deffn
564 @deffn {Procedure} set-vec3-y! @var{v} @var{y}
565 Set the Y coordinate of the 3D vector @var{v} to @var{y}.
566 @end deffn
568 @deffn {Procedure} set-vec3-z! @var{v} @var{z}
569 Set the Z coordinate of the 3D vector @var{v} to @var{z}.
570 @end deffn
572 @deffn {Procedure} vec3-copy! @var{source} @var{target}
573 Copy the 3D vector @var{source} into the 3D vector @var{target}.
574 @end deffn
576 @deffn {Procedure} vec3-add! @var{v} @var{x}
577 Perform an in-place modification of the 3D vector @var{v} by adding
578 @var{x}, a 3D vector or a scalar.
579 @end deffn
581 @deffn {Procedure} vec3-sub! @var{v} @var{x}
582 Perform an in-place modification of the 3D vector @var{v} by
583 subtracting @var{x}, a 3D vector or a scalar.
584 @end deffn
586 @deffn {Procedure} vec3-mult! @var{v} @var{x}
587 Perform an in-place modification of the 3D vector @var{v} by
588 multiplying it by @var{x}, a 3D vector or a scalar.
589 @end deffn
591 @node Rectangles
592 @subsection Rectangles
594 The @code{(chickadee math rect)} module provides an API for
595 manipulating axis-aligned bounding boxes (AABBs). AABBs are often
596 used for collision detection in games. Common use-cases are defining
597 ``hitboxes'' in platformers or using them for the ``broad phase'' of a
598 collision detection algorithm that uses a more complex (and thus
599 slower) method of determining the actual collisions.
601 Like some of the other math modules, there exists a collection of
602 functions that do in-place modification of rectangles for use in
603 performance critical code paths.
605 @deffn {Procedure} make-rect @var{x} @var{y} @var{width} @var{height}
606 Create a new rectangle that is @var{width} by @var{height} in size and
607 whose bottom-left corner is located at (@var{x}, @var{y}).
608 @end deffn
610 @deffn {Procedure} rect? @var{obj}
611 Return @code{#t} if @var{obj} is a rectangle.
612 @end deffn
614 @deffn {Procedure} rect-within? @var{rect1} @var{rect2}
615 Return @code{#t} if @var{rect2} is completely within @var{rect1}.
616 @end deffn
618 @deffn {Procedure} rect-intersects? @var{rect1} @var{rect2}
619 Return @code{#t} if @var{rect2} overlaps @var{rect1}.
620 @end deffn
622 @deffn {Procedure} rect-contains? @var{rect} @var{x} @var{y}
623 Return @code{#t} if the coordinates (@var{x}, @var{y}) are within
624 @var{rect}.
625 @end deffn
627 @deffn {Procedure} rect-contains-vec2? @var{rect} @var{v}
628 Return @code{#t} if the 2D vector @var{v} is within the bounds of
629 @var{rect}.
630 @end deffn
632 @deffn {Procedure} rect-x @var{rect}
633 Return the X coordinate of the lower-left corner of @var{rect}.
634 @end deffn
636 @deffn {Procedure} rect-y @var{rect}
637 Return the Y coordinate of the lower-left corner of @var{rect}.
638 @end deffn
640 @deffn {Procedure} rect-left @var{rect}
641 Return the left-most X coordinate of @var{rect}.
642 @end deffn
644 @deffn {Procedure} rect-right @var{rect}
645 Return the right-most X coordinate of @var{rect}.
646 @end deffn
648 @deffn {Procedure} rect-bottom @var{rect}
649 Return the bottom-most Y coordinate of @var{rect}.
650 @end deffn
652 @deffn {Procedure} rect-top @var{rect}
653 Return the top-most Y coordinate of @var{rect}.
654 @end deffn
656 @deffn {Procedure} rect-center-x @var{rect}
657 Return the X coordinate of the center of @var{rect}.
658 @end deffn
660 @deffn {Procedure} rect-center-y @var{rect}
661 Return the Y coordinate of the center of @var{rect}.
662 @end deffn
664 @deffn {Procedure} rect-width @var{rect}
665 Return the width of @var{rect}.
666 @end deffn
668 @deffn {Procedure} rect-height @var{rect}
669 Return the height of @var{rect}.
670 @end deffn
672 @deffn {Procedure} rect-area @var{rect}
673 Return the surface area covered by @var{rect}.
674 @end deffn
676 @deffn {Procedure} rect-clamp-x @var{rect} @var{x}
677 Restrict @var{x} to the portion of the X axis covered by @var{rect}.
678 @end deffn
680 @deffn {Procedure} rect-clamp-y @var{rect} @var{y}
681 Restrict @var{y} to the portion of the Y axis covered by @var{rect}.
682 @end deffn
684 @deffn {Procedure} rect-clamp @var{rect1} @var{rect2}
685 Return a new rect that adjusts the location of @var{rect1} so that it
686 is completely within @var{rect2}. An exception is thrown in the case
687 that @var{rect1} cannot fit completely within @var{rect2}.
688 @end deffn
690 @deffn {Procedure} rect-move @var{rect} @var{x} @var{y}
691 Return a new rectangle based on @var{rect} but moved to the
692 coordinates (@var{x}, @var{y}).
693 @end deffn
695 @deffn {Procedure} rect-move-vec2 @var{rect} @var{v}
696 Return a new rectangle based on @var{rect} but moved to the
697 coordinates in the 2D vector @var{v}.
698 @end deffn
700 @deffn {Procedure} rect-move-by @var{rect} @var{x} @var{y}
701 Return a new rectangle based on @var{rect} but moved by (@var{x},
702 @var{y}) units relative to its current location.
703 @end deffn
705 @deffn {Procedure} rect-move-by-vec2 @var{rect} @var{v}
706 Return a new rectangle based on @var{rect} but moved by the 2D vector
707 @var{v} relative to its current location.
708 @end deffn
710 @deffn {Procedure} rect-inflate @var{rect} @var{width} @var{height}
711 Return a new rectangle based on @var{rect}, but expanded by
712 @var{width} units on the X axis and @var{height} units on the Y axis,
713 while keeping the rectangle centered on the same point.
714 @end deffn
716 @deffn {Procedure} rect-union @var{rect1} @var{rect2}
717 Return a new rectangle that completely covers the area of @var{rect1}
718 and @var{rect2}.
719 @end deffn
721 @deffn {Procedure} rect-clip @var{rect1} @var{rect2}
722 Return a new rectangle that is the overlapping region of @var{rect1}
723 and @var{rect2}. If the two rectangles do not overlap, a rectangle of
724 0 width and 0 height is returned.
725 @end deffn
727 @deffn {Procedure} set-rect-x! @var{rect} @var{x}
728 Set the left X coordinate of @var{rect} to @var{x}.
729 @end deffn
731 @deffn {Procedure} set-rect-y! @var{rect} @var{y}
732 Set the bottom Y coordinate of @var{rect} to @var{y}.
733 @end deffn
735 @deffn {Procedure} set-rect-width! @var{rect} @var{width}
736 Set the width of @var{rect} to @var{width}.
737 @end deffn
739 @deffn {Procedure} set-rect-height! @var{rect} @var{height}
740 Set the height of @var{rect} to @var{height}.
741 @end deffn
743 @deffn {Procedure} rect-move! @var{rect} @var{x} @var{y}
744 Move @var{rect} to (@var{x}, @var{y}) in-place.
745 @end deffn
747 @deffn {Procedure} rect-move-vec2! @var{rect} @var{v}
748 Move @var{rect} to the 2D vector @var{v} in-place.
749 @end deffn
751 @deffn {Procedure} rect-move-by! @var{rect} @var{x} @var{y}
752 Move @var{rect} by (@var{x}, @var{y}) in-place.
753 @end deffn
755 @deffn {Procedure} rect-move-by-vec2! @var{rect} @var{v}
756 Move @var{rect} by the 2D vector @var{v} in-place.
757 @end deffn
759 @deffn {Procedure} rect-inflate! @var{rect} @var{width} @var{height}
760 Expand @var{rect} by @var{width} and @var{height} in-place.
761 @end deffn
763 @deffn {Procedure} rect-union! @var{rect1} @var{rect2}
764 Modify @var{rect1} in-place to completely cover the area of both
765 @var{rect1} and @var{rect2}.
766 @end deffn
768 @deffn {Procedure} rect-clip! @var{rect1} @var{rect2}
769 Modify @var{rect1} in-place to be the overlapping region of
770 @var{rect1} and @var{rect2}.
771 @end deffn
773 @deffn {Procedure} rect-clamp! @var{rect1} @var{rect2}
774 Adjust the location of @var{rect1} in-place so that its bounds are
775 completely within @var{rect2}. An exception is thrown in the case
776 that @var{rect1} cannot fit completely within @var{rect2}.
777 @end deffn
779 @deffn {Procedure} vec2-clamp-to-rect! @var{v} @var{rect}
780 Restrict the coordinates of the 2D vector @var{v} so that they are
781 within the bounds of @var{rect}. @var{v} is modified in-place.
782 @end deffn
784 @node Matrices
785 @subsection Matrices
787 The @code{(chickadee math matrix)} module provides an interface for
788 working with the most common type of matrices in game development: 4x4
789 transformation matrices.
791 @subsubsection Another Note About Performance
793 Much like the vector API, the matrix API is commonly used in
794 performance critical code paths. In order to reduce the amount of
795 garbage generated and improve matrix multiplication performance, there
796 are many procedures that perform in-place modifications of matrix
797 objects.
799 @subsubsection Matrix Operations
801 @deffn {Procedure} make-matrix4 @var{aa} @var{ab} @var{ac} @var{ad} @
802 @var{ba} @var{bb} @var{bc} @var{bd} @
803 @var{ca} @var{cb} @var{cc} @var{cd} @
804 @var{da} @var{db} @var{dc} @var{dd}
806 Return a new 4x4 matrix initialized with the given 16 values in
807 column-major format.
808 @end deffn
810 @deffn {Procedure} make-null-matrix4
811 Return a new 4x4 matrix with all values initialized to 0.
812 @end deffn
814 @deffn {Procedure} make-identity-matrix4
815 Return a new 4x4 identity matrix. Any matrix multiplied by the
816 identity matrix yields the original matrix. This procedure is
817 equivalent to the following code:
819 @example
820 (make-matrix4 1 0 0 0
821 0 1 0 0
822 0 0 1 0
823 0 0 0 1)
824 @end example
826 @end deffn
828 @deffn {Procedure} matrix4? @var{obj}
829 Return @code{#t} if @var{obj} is a 4x4 matrix.
830 @end deffn
832 @deffn {Procedure} matrix4* . @var{matrices}
833 Return a new 4x4 matrix containing the product of multiplying all of
834 the given @var{matrices}.
836 Note: Remember that matrix multiplication is @strong{not} commutative!
837 @end deffn
839 @deffn {Procedure} orthographic-projection @var{left} @var{right} @
840 @var{top} @var{bottom} @
841 @var{near} @var{far}
843 Return a new 4x4 matrix that represents an orthographic (2D)
844 projection for the horizontal clipping plane @var{top} and
845 @var{bottom}, the vertical clipping plane @var{top} and @var{bottom},
846 and the depth clipping plane @var{near} and @var{far}.
847 @end deffn
849 @deffn {Procedure} perspective-projection @var{fov} @
850 @var{aspect-ratio} @
851 @var{near} @var{far}
853 Return a new 4x4 matrix that represents a perspective (3D) projection
854 with a field of vision of @var{fov} radians, an aspect ratio of
855 @var{aspect-ratio}, and a depth clipping plane defined by @var{near}
856 and @var{far}.
857 @end deffn
859 @deffn {Procedure} matrix4-translate @var{x}
860 Return a new 4x4 matrix that represents a translation by @var{x}, a 2D
861 vector, a 3D vector, or a rectangle (in which case the bottom-left
862 corner of the rectangle is used).
863 @end deffn
865 @deffn {Procedure} matrix4-scale @var{s}
866 Return a new 4x4 matrix that represents a scaling along the X, Y, and
867 Z axes by the scaling factor @var{s}, a real number.
868 @end deffn
870 @deffn {Procedure} matrix4-rotate @var{q}
871 Return a new 4x4 matrix that represents a rotation about an arbitrary
872 axis defined by the quaternion @var{q}.
873 @end deffn
875 @deffn {Procedure} matrix4-rotate-z @var{theta}
876 Return a new 4x4 matrix that represents a rotation about the Z axis by
877 @var{theta} radians.
878 @end deffn
880 @deffn {Procedure} matrix4-identity! @var{matrix}
881 Modify @var{matrix} in-place to contain the identity matrix.
882 @end deffn
884 @deffn {Procedure} matrix4-mult! @var{dest} @var{a} @var{b}
885 Multiply the 4x4 matrix @var{a} by the 4x4 matrix @var{b} and store
886 the result in the 4x4 matrix @var{dest}.
887 @end deffn
889 @deffn {Procedure} matrix4-translate! @var{matrix} @var{x}
890 Modify @var{matrix} in-place to contain a translation by @var{x}, a 2D
891 vector, a 3D vector, or a rectangle (in which case the bottom-left
892 corner of the rectangle is used).
893 @end deffn
895 @deffn {Procedure} matrix4-scale! @var{matrix} @var{s}
896 Modify @var{matrix} in-place to contain a scaling along the X, Y, and
897 Z axes by the scaling factor @var{s}, a real number.
898 @end deffn
900 @deffn {Procedure} matrix4-rotate! @var{matrix} @var{q}
901 Modify @var{matrix} in-place to contain a rotation about an arbitrary
902 axis defined by the quaternion @var{q}.
903 @end deffn
905 @deffn {Procedure} matrix4-rotate-z! @var{matrix} @var{theta}
906 Modify @var{matrix} in-place to contain a rotation about the Z axis by
907 @var{theta} radians.
908 @end deffn
910 @deffn {Procedure} matrix4-2d-transform! @var{matrix} [#:origin] @
911 [#:position] [#:rotation] @
912 [#:scale] [#:skew]
914 Modify @var{matrix} in-place to contain the transformation described
915 by @var{position}, a 2D vector or rectangle, @var{rotation}, a scalar
916 representing a rotation about the Z axis, @var{scale}, a 2D vector,
917 and @var{skew}, a 2D vector. The transformation happens with respect
918 to @var{origin}, a 2D vector. If an argument is not provided, that
919 particular transformation will not be included in the result.
920 @end deffn
922 @deffn {Procedure} transform! @var{matrix} @var{v}
923 Modify the 2D vector @var{v} in-place by multiplying it by the 4x4
924 matrix @var{matrix}.
925 @end deffn
927 @node Quaternions
928 @subsection Quaternions
930 In game development, the quaternion is most often used to represent
931 rotations. Why not use a matrix for that, you may ask. Unlike
932 matrices, quaternions can be interpolated (animated) and produce a
933 meaningful result. When interpolating two quaternions, there is a
934 smooth transition from one rotation to another, whereas interpolating
935 two matrices would yield garbage.
937 @deffn {Procedure} quaternion @var{x} @var{y} @var{z} @var{w}
938 Return a new quaternion with values @var{x}, @var{y}, @var{z}, and
939 @var{w}.
940 @end deffn
942 @deffn {Procedure} quaternion? @var{obj}
943 Return @code{#t} if @var{obj} is a quaternion.
944 @end deffn
946 @deffn {Procedure} quaternion-w @var{q}
947 Return the W component of the quaternion @var{q}.
948 @end deffn
950 @deffn {Procedure} quaternion-x @var{q}
951 Return the X component of the quaternion @var{q}.
952 @end deffn
954 @deffn {Procedure} quaternion-y @var{q}
955 Return the Y component of the quaternion @var{q}.
956 @end deffn
958 @deffn {Procedure} quaternion-z @var{q}
959 Return the Z component of the quaternion @var{q}.
960 @end deffn
962 @deffn {Procedure} make-identity-quaternion
963 Return the identity quaternion.
964 @end deffn
966 @node Easings
967 @subsection Easings
969 @deffn {Procedure} linear @var{t}
970 @end deffn
972 @deffn {Procedure} smoothstep @var{t}
973 @end deffn
975 @deffn {Procedure} ease-in-quad @var{t}
976 @end deffn
978 @deffn {Procedure} ease-out-quad @var{t}
979 @end deffn
981 @deffn {Procedure} ease-in-out-quad @var{t}
982 @end deffn
984 @deffn {Procedure} ease-in-cubic @var{t}
985 @end deffn
987 @deffn {Procedure} ease-out-cubic @var{t}
988 @end deffn
990 @deffn {Procedure} ease-in-out-cubic @var{t}
991 @end deffn
993 @deffn {Procedure} ease-in-quart @var{t}
994 @end deffn
996 @deffn {Procedure} ease-out-quart @var{t}
997 @end deffn
999 @deffn {Procedure} ease-in-out-quart @var{t}
1000 @end deffn
1002 @deffn {Procedure} ease-in-quint @var{t}
1003 @end deffn
1005 @deffn {Procedure} ease-out-quint @var{t}
1006 @end deffn
1008 @deffn {Procedure} ease-in-out-quint @var{t}
1009 @end deffn
1011 @deffn {Procedure} ease-in-sine @var{t}
1012 @end deffn
1014 @deffn {Procedure} ease-out-sine @var{t}
1015 @end deffn
1017 @deffn {Procedure} ease-in-out-sine @var{t}
1018 @end deffn
1020 @node Bezier Curves
1021 @subsection Bezier Curves
1023 The @code{(chickadee math bezier)} module provides an API for
1024 describing cubic Bezier curves in 2D space. These curves are notably
1025 used in font description, vector graphics programs, and when it comes
1026 to games: path building. With Bezier curves, it's somewhat easy to
1027 create a smooth looking path for an enemy to move along, for example.
1028 Bezier curves become particularly interesting when they are chained
1029 together to form a Bezier ``path'', where the end point of one curve
1030 becomes the starting point of the next.
1032 Currently, the rendering of Bezier curves is rather crude and provided
1033 mostly for visualizing and debugging curves that would be unseen in
1034 the final game. See @xref{Lines and Shapes} for more information.
1036 @deffn {Procedure} make-bezier-curve @var{p0} @var{p1} @var{p2} @var{p3}
1037 Return a new Bezier curve object whose starting point is @var{p0},
1038 ending point is @var{p3}, and control points are @var{p1} and
1039 @var{p2}. All points are 2D vectors.
1040 @end deffn
1042 @deffn {Procedure} bezier-curve? @var{obj}
1043 Return @code{#t} if @var{obj} is a Bezier curve.
1044 @end deffn
1046 @deffn {Procedure} bezier-curve-p0 @var{bezier}
1047 Return the starting point of @var{bezier}.
1048 @end deffn
1050 @deffn {Procedure} bezier-curve-p1 @var{bezier}
1051 Return the first control point of @var{bezier}.
1052 @end deffn
1054 @deffn {Procedure} bezier-curve-p2 @var{bezier}
1055 Return the second control point of @var{bezier}.
1056 @end deffn
1058 @deffn {Procedure} bezier-curve-p3 @var{bezier}
1059 Return the end point of @var{bezier}.
1060 @end deffn
1062 @deffn {Procedure} bezier-path . @var{control-points}
1063 Return a list of connected bezier curves defined by
1064 @var{control-points}. The first curve is defined by the first 4
1065 arguments and every additional curve thereafter requires 3 additional
1066 arguments.
1067 @end deffn
1069 @deffn {Procedure} bezier-curve-point-at @var{bezier} @var{t}
1070 Return the coordinates for @var{bezier} at @var{t} (a value in the
1071 range [0, 1] representing how far from the start of the curve to
1072 check) as a 2D vector.
1073 @end deffn
1075 @deffn {Procedure} bezier-curve-point-at! @var{dest} @var{bezier} @var{t}
1076 Modify the 2D vector @var{dest} in-place to contain the coordinates
1077 for @var{bezier} at @var{t}.
1078 @end deffn
1080 @node Graphics
1081 @section Graphics
1083 Chickadee aims to make hardware-accelerated graphics rendering as
1084 simple and efficient as possible by providing high-level APIs that
1085 interact with the low-level OpenGL API under the hood. Anyone that
1086 has worked with OpenGL directly knows that it has a steep learning
1087 curve and a lot of effort is needed to render even a single triangle.
1088 The Chickadee rendering engine attempts to make it easy to do common
1089 tasks like rendering a sprite while also providing all of the building
1090 blocks to implement additional rendering techniques.
1092 @menu
1093 * Rendering Engine:: Rendering state management.
1094 * Textures:: 2D images.
1095 * Sprites:: Draw 2D images.
1096 * Tile Maps:: Draw 2D tile maps.
1097 * Lines and Shapes:: Draw line segments and polygons.
1098 * Fonts:: Drawing text.
1099 * Blending and Depth Testing:: Control how pixels are combined.
1100 * Vertex Arrays:: Create 2D/3D models.
1101 * Shaders:: Create custom GPU programs.
1102 * Framebuffers:: Render to texture.
1103 * Viewports:: Restrict rendering to
1104 @end menu
1106 @node Rendering Engine
1107 @subsection Rendering Engine
1109 Chickadee defines rendering using a metaphor familiar to Scheme
1110 programmers: procedure application. A shader (@pxref{Shaders}) is
1111 like a procedure for the GPU to apply. Shaders are passed arguments:
1112 A vertex array containing the geometry to render (@pxref{Vertex
1113 Arrays}) and zero or more keyword arguments that the shader
1114 understands. Similar to how Scheme has @code{apply} for calling
1115 procedures, Chickadee provides @code{gpu-apply} for calling shaders.
1117 Additionally, there is some dynamic state that effects how
1118 @code{gpu-apply} will behave. Things like the current viewport,
1119 framebuffer, and blend mode are stored as dynamic state because it
1120 would be tedious to have to have to specify them each time
1121 @code{gpu-apply} is called.
1123 The following procedures and syntax can be found in the
1124 @code{(chickadee render)} module.
1126 @deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
1127 [#:uniform-key @var{uniform-value} ...]
1128 @deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
1129 @var{count} [#:uniform-key @var{uniform-value} ...]
1131 Render @var{vertex-array} using @var{shader} with the uniform values
1132 specified in the following keyword arguments.
1134 While @code{gpu-apply} will draw every vertex in @var{vertex-array},
1135 @code{gpu-apply*} will only draw @var{count} vertices.
1137 @end deffn
1139 @deffn {Procedure} current-viewport
1140 Return the currently bound viewport (@pxref{Viewports}).
1141 @end deffn
1143 @deffn {Procedure} current-framebuffer
1144 Return the currently bound framebuffer (@pxref{Framebuffers}).
1145 @end deffn
1147 @deffn {Procedure} current-blend-mode
1148 Return the currently bound blend mode (@pxref{Blending and Depth
1149 Testing}).
1150 @end deffn
1152 @deffn {Procedure} current-depth-test
1153 Return @code{#t} if depth testing is currently enabled (@pxref{Blending and Depth Testing}).
1154 @end deffn
1156 @deffn {Procedure} current-texture
1157 Return the currently bound texture (@pxref{Textures}).
1158 @end deffn
1160 @deffn {Procedure} current-projection
1161 Return the currently bound projection matrix (@pxref{Matrices}).
1162 @end deffn
1164 @deffn {Syntax} with-viewport @var{viewport} @var{body} ...
1165 Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
1166 @end deffn
1168 @deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
1169 Evaluate @var{body} with the current framebuffer bound to
1170 @var{framebuffer} (@pxref{Framebuffers}).
1171 @end deffn
1173 @deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
1174 Evaluate @var{body} with the current blend mode bound to
1175 @var{blend-mode} (@pxref{Blending and Depth Testing}).
1176 @end deffn
1178 @deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
1179 Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
1180 is @code{#f}, or enabled otherwise (@pxref{Blending and Depth
1181 Testing}).
1182 @end deffn
1184 @deffn {Syntax} with-texture @var{texture} @var{body} ...
1185 Evaluate @var{body} with the current texture bound to @var{texture}
1186 (@pxref{Textures}).
1187 @end deffn
1189 @deffn {Syntax} with-projection @var{projection} @var{body} ...
1190 Evaluate @var{body} with the current projection matrix bound to
1191 @var{projection} (@pxref{Matrices}).
1192 @end deffn
1194 @node Textures
1195 @subsection Textures
1197 @deffn {Procedure} load-image @var{file} [#:min-filter nearest] @
1198 [#:mag-filter nearest] [#:wrap-s repeat] [#:wrap-t repeat]
1200 Load the image data from @var{file} and return a new texture object.
1202 @var{min-filter} and @var{mag-filter} describe the method that should
1203 be used for minification and magnification when rendering,
1204 respectively. Possible values are @code{nearest} and @code{linear}.
1206 @var{wrap-s} and @var{wrap-t} describe how to interpret texture
1207 coordinates that are greater than @code{1.0}. Possible values are
1208 @code{repeat}, @code{clamp}, @code{clamp-to-border}, and
1209 @code{clamp-to-edge}.
1211 @end deffn
1213 @node Sprites
1214 @subsection Sprites
1216 For those who are new to this game, a sprite is a 2D rectangular
1217 bitmap that is rendered to the screen. For 2D games, sprites are the
1218 most essential graphical abstraction. They are used for drawing maps,
1219 players, NPCs, items, particles, text, etc. In Chickadee, bitmaps are
1220 stored in textures (@pxref{Textures}) and can be used to draw sprites
1221 via the @code{draw-sprite} procedure.
1223 @deffn {Procedure} draw-sprite @var{texture} @var{position} @
1224 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1225 [#:rect] [#:shader]
1227 Draw @var{texture} at @var{position}.
1229 Optionally, other transformations may be applied to the sprite.
1230 @var{rotation} specifies the angle to rotate the sprite, in radians.
1231 @var{scale} specifies the scaling factor as a 2D vector. All
1232 transformations are applied relative to @var{origin}, a 2D vector,
1233 which defaults to the lower-left corner.
1235 Alpha blending is used by default but the blending method can be
1236 changed by specifying @var{blend-mode}.
1238 The area drawn to is as big as the texture, by default. To draw to an
1239 arbitrary section of the screen, specify @var{rect}.
1241 Finally, advanced users may specify @var{shader} to change the way the
1242 sprite is rendered entirely.
1243 @end deffn
1245 It's not uncommon to need to draw hundreds or thousands of sprites
1246 each frame. However, GPUs (graphics processing units) are tricky
1247 beasts that prefer to be sent few, large chunks of data to render
1248 rather than many, small chunks. Using @code{draw-sprite} on its own
1249 will involve at least one GPU call @emph{per sprite}, which will
1250 quickly lead to poor performance. To deal with this, a technique
1251 known as ``sprite batching'' can be used. Instead of drawing each
1252 sprite immediately, the sprite batch will build up a large of buffer
1253 of sprites to draw and defer rendering until the last possible moment.
1254 Batching isn't a panacea, though. Batching only works if the sprites
1255 being drawn share as much in common as possible. Every time you draw
1256 a sprite with a different texture or blend mode, the batch will be
1257 sent off to the GPU. Therefore, batching is most useful if you
1258 minimize such changes. A good strategy for reducing texture changes
1259 is to stuff many bitmaps into a single image file and create a
1260 ``texture atlas'' (@pxref{Textures}) to access the sub-images within.
1262 Taking advantage of sprite batching in Chickadee is easy, just wrap
1263 the code that is calling @code{draw-sprite} a lot in the
1264 @code{with-batched-sprites} form.
1266 @deffn {Syntax} with-batched-sprites @var{body} @dots{}
1267 Use batched rendering for all @code{draw-sprite} calls within
1268 @var{body}.
1269 @end deffn
1271 With a basic sprite abstraction in place, it's possible to build other
1272 abstractions on top of it. One such example is the ``nine patch''. A
1273 nine patch is a sprite that can be rendered at various sizes without
1274 becoming distorted. This is achieved by diving up the sprite into
1275 nine regions:
1277 @itemize
1278 @item
1279 the center, which can be scaled horizontally and vertically
1280 @item
1281 the four corners, which can never be scaled
1282 @item
1283 the left and right sides, which can be scaled vertically
1284 @item
1285 the top and bottom sides, which can be scaled horizontally
1286 @end itemize
1288 The one caveat is that the bitmap regions must be designed in such a
1289 way so that they are not distorted when stretched along the affected
1290 axes. For example, that means that the top and bottom sides could
1291 have varying colored pixels vertically, but not horizontally.
1293 The most common application of this technique is for graphical user
1294 interface widgets like buttons and dialog boxes. By using a nine
1295 patch, they can be rendered at any size without unappealing scaling
1296 artifacts.
1298 @deffn {Procedure} draw-nine-patch @var{texture} @var{rect} @
1299 [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] @
1300 [#:left-margin margin] [#:right-margin margin] @
1301 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1302 [#:shader]
1304 Draw a nine patch sprite. A nine patch sprite renders @var{texture}
1305 as a @var{width} x @var{height} rectangle whose stretchable areas are
1306 defined by the given margin measurements @var{top-margin},
1307 @var{bottom-margin}, @var{left-margin}, and @var{right-margin}. The
1308 @var{margin} argument may be used to configure all four margins at
1309 once.
1311 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1312 the other arguments.
1313 @end deffn
1315 @node Tile Maps
1316 @subsection Tile Maps
1318 A tile map is a scene created by composing lots of small sprites,
1319 called ``tiles'', into a larger image. One program for editing such
1320 maps is called @url{,Tiled}. Chickadee has native
1321 support for loading and rendering Tiled maps in the @code{(chickadee
1322 render tiled)} module.
1324 @deffn {Procedure} load-tile-map @var{file-name}
1325 Load the Tiled formatted map in @var{file-name} and return a new tile
1326 map object.
1327 @end deffn
1329 @deffn {Procedure} draw-tile-map @var{tile-map} [#:layers] [#:region] @
1330 [#:origin] [#:position] [#:scale] [#:rotation]
1332 Draw the layers of @var{tile-map}. By default, all layers are drawn.
1333 To draw a subset of the available layers, pass a list of layer ids
1334 using the @var{layers} keyword argument.
1336 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1337 the other arguments.
1338 @end deffn
1340 @node Lines and Shapes
1341 @subsection Lines and Shapes
1343 Sprites are fun, but sometimes simple, untextured lines and polygons
1344 are desired. That's where the @code{(chickadee render shapes)} module
1345 comes in!
1347 @deffn {Procedure} draw-line @var{start} @var{end} @
1348 [#:thickness 0.5] [#:feather 1.0] [#:cap round] [#:color] @
1349 [#:shader]
1351 Draw a line segment from @var{start} to @var{end}. The line will be
1352 @var{thickness} pixels thick with an antialiased border @var{feather}
1353 pixels wide. The line will be colored @var{color}. @var{cap}
1354 specifies the type of end cap that should be used to terminate the
1355 lines, either @code{none}, @code{butt}, @code{square}, @code{round},
1356 @code{triangle-in}, or @code{triangle-out}. Advanced users may use
1357 the @var{shader} argument to override the built-in line segment
1358 shader.
1359 @end deffn
1361 @deffn {Procedure} draw-bezier-curve @var{bezier} [#:segments 32] @
1362 [#:control-points?] [#:tangents?] @
1363 [#:control-point-size 8] @
1364 [#:control-point-color yellow] @
1365 [#:tangent-color yellow] @
1366 [#:thickness 0.5] [#:feather 1.0] @
1367 [#:matrix]
1369 Draw the curve defined by @var{bezier} using a resolution of N
1370 @var{segments}. When @var{control-points?} is @code{#t}, the control
1371 points are rendered as squares of size @var{control-point-size} pixels
1372 and a color of @var{control-point-color}. When @var{tangents?} is
1373 @code{#t}, the tangent lines from terminal point to control point are
1374 rendered using the color @var{tangent-color}.
1376 All line segments rendered use @code{draw-line}, and thus the
1377 arguments @var{thickness} and @var{feather} have the same effect as in
1378 that procedure.
1380 A custom @var{matrix} may be passed for applications that require more
1381 control over the final output.
1382 @end deffn
1384 @deffn {Procedure} draw-bezier-path @var{path} [#:segments 32] @
1385 [#:control-points?] [#:tangents?] @
1386 [#:control-point-size 8] @
1387 [#:control-point-color yellow] @
1388 [#:tangent-color yellow] @
1389 [#:thickness 0.5] [#:feather 1.0] @
1390 [#:matrix]
1392 Render @var{path}, a list of bezier curves. See the documentation for
1393 @code{draw-bezier-curve} for an explanation of all the keyword
1394 arguments.
1395 @end deffn
1397 @node Fonts
1398 @subsection Fonts
1400 Unlike the traditional TrueType font format that many are accustomed
1401 to, Chickadee loads and renders bitmap fonts in the
1402 @url{,
1403 Angel Code format}. But why use this seemingly obscure format? It's
1404 easy to find TTFs but not easy to find FNTs (the canonical file
1405 extension used for Angel Code fonts) and bitmap fonts don't scale
1406 well. The reason is efficiency.
1408 If all of the glyphs of a font are pre-rendered and packed into an
1409 image file then it becomes possible to use a texture atlas
1410 (@pxref{Textures}) and a sprite batch (@pxref{Sprites}) when
1411 rendering, which is a more efficient way to render fonts than using,
1412 say, @url{, SDL_ttf} or other
1413 solutions that involve using the FreeType library directly.
1415 Now what about scaling? In libraries that use TTF fonts, one must
1416 choose the size that the glyphs will be rasterized at up front. To
1417 use @code{n} sizes of the same font, one must load @code{n} variants
1418 of that font. If the size of the text is dynamic, some kind of
1419 texture scaling algorithm must be used and the text will inevitably
1420 look blurry. At first glance, using bitmap fonts seem to have an even
1421 worse issue. Instead of just loading the same font @code{n} times at
1422 different sizes, one would need to generate @code{n} image files for
1423 each font size needed. This is where the ``signed distance field''
1424 rendering technique comes in. Introduced by
1425 @url{,
1426 Valve} in 2007, signed distance field fonts can be efficiently stored
1427 in a bitmap and be rendered at arbitrary scale factors with good
1428 results.
1430 While Chickadee does not yet offer a tool for converting TTF fonts
1431 into FNT fonts, tools such as
1432 @url{, Hiero} may be used
1433 in the meantime.
1435 The following procedures can be found in the @code{(chickadee render
1436 font)} module.
1438 @deffn {Procedure} load-font @var{file}
1439 Load the Angel Code formatted XML document in @var{file} and return a
1440 new font object.
1441 @end deffn
1443 @deffn {Procedure} font? @var{obj}
1444 Return @code{#t} if @var{obj} is a font object.
1445 @end deffn
1447 @deffn {Procedure} font-face @var{font}
1448 Return the name of @var{font}.
1449 @end deffn
1451 @deffn {Procedure} font-line-height @var{font}
1452 Return the line height of @var{font}.
1453 @end deffn
1455 @deffn {Procedure} font-line-height @var{font}
1456 Return the line height of @var{font}.
1457 @end deffn
1459 @deffn {Procedure} font-bold? @var{font}
1460 Return @code{#t} if @var{font} is a bold font.
1461 @end deffn
1463 @deffn {Procedure} font-italic? @var{font}
1464 Return @code{#t} if @var{font} is an italicized font.
1465 @end deffn
1467 @deffn {Procedure} draw-text @var{font} @var{text} @var{position}
1468 [#:origin] [#:scale] [#:rotation] [#:blend-mode]
1469 [#:start 0] [#:end @code{(string-length text)}]
1471 Draw the string @var{text} with the first character starting at
1472 @var{position} using @var{font}.
1474 @example
1475 (draw-text font "Hello, world!" (vec2 128.0 128.0))
1476 @end example
1478 To render a substring of @var{text}, use the @var{start} and @var{end}
1479 arguments.
1481 Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1482 the other arguments.
1483 @end deffn
1485 @node Blending and Depth Testing
1486 @subsection Blending and Depth Testing
1488 @node Vertex Arrays
1489 @subsection Vertex Arrays
1491 @node Shaders
1492 @subsection Shaders
1494 Shaders are programs for the GPU to evaluate. They are written in the
1495 OpenGL Shading Language, or GLSL. Chickadee does not currently
1496 provide a Scheme-like domain specific language for writing shaders.
1497 Since shaders must be written in GLSL and not Scheme, they are
1498 considered an advanced feature.
1500 @node Framebuffers
1501 @subsection Framebuffers
1503 A framebuffer is a chunk of memory that the GPU can render things
1504 onto. By default, the framebuffer that is used for rendering is the
1505 one belonging to the game window, but custom framebuffers can be used
1506 as well. A common use-case for custom framebuffers is applying
1507 post-processing effects: The entire scene is rendered to a
1508 framebuffer, and then the contents of that framebuffer are applied to
1509 a post-processing shader and rendered to the game window. The
1510 post-processing shader could do any number of things: scaling,
1511 antialiasing, motion blur, etc.
1513 @deffn {Procedure} make-framebuffer @var{width} @var{height} [#:min-filter 'linear] [#:mag-filter 'linear] [#:wrap-s 'repeat] [#:wrap-t 'repeat]
1515 Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high.
1517 @var{min-filter} and @var{mag-filter} determine the scaling algorithm
1518 applied to the framebuffer when rendering. By default, linear scaling
1519 is used in both cases. To perform no smoothing at all, use
1520 @code{nearest} for simple nearest neighbor scaling. This is typically
1521 the best choice for pixel art games.
1522 @end deffn
1524 @deffn {Procedure} framebuffer? @var{obj}
1525 Return @code{#t} if @var{obj} is a framebuffer.
1526 @end deffn
1528 @deffn {Procedure} framebuffer-texture @var{fb}
1529 Return the texture backing the framebuffer @var{fb}.
1530 @end deffn
1532 @deffn {Procedure} framebuffer-viewport @var{fb}
1533 Return the default viewport (@pxref{Viewports}) used by the
1534 framebuffer @var{fb}.
1535 @end deffn
1537 @deffn {Procedure} null-framebuffer
1538 The default framebuffer.
1539 @end deffn
1541 @node Viewports
1542 @subsection Viewports
1544 @node Scripting
1545 @section Scripting
1547 Game logic is a web of asynchronous events that are carefully
1548 coordinated to bring the game world to life. In order to make an
1549 enemy follow and attack the player, or move an NPC back and forth in
1550 front of the item shop, or do both at the same time, a scripting
1551 system is a necessity. Chickadee comes with an asynchronous
1552 programming system in the @code{(chickadee scripting)} module.
1553 Lightweight, cooperative threads known as ``scripts'' allow the
1554 programmer to write asynchronous code as if it were synchronous, and
1555 allow many such ``threads'' to run concurrently.
1557 But before we dig deeper into scripts, let's discuss the simple act
1558 of scheduling tasks.
1560 @menu
1561 * Agendas:: Scheduling tasks.
1562 * Scripts:: Cooperative multitasking.
1563 * Tweening:: Animations.
1564 * Channels:: Publish data to listeners.
1565 @end menu
1567 @node Agendas
1568 @subsection Agendas
1570 To schedule a task to be performed later, an ``agenda'' is used.
1571 There is a default, global agenda that is ready to be used, or
1572 additional agendas may be created for different purposes. The
1573 following example prints the text ``hello'' when the agenda has
1574 advanced to time unit 10.
1576 @example
1577 (at 10 (display "hello\n"))
1578 @end example
1580 Most of the time it is more convenient to schedule tasks relative to
1581 the current time. This is where @code{after} comes in handy:
1583 @example
1584 (after 10 (display "hello\n"))
1585 @end example
1587 Time units in the agenda are in no way connected to real time. It's
1588 up to the programmer to decide what agenda time means. A simple and
1589 effective approach is to map each call of the update hook
1590 (@pxref{Kernel}) to 1 unit of agenda time, like so:
1592 @example
1593 (add-hook! update-hook (lambda (dt) (update-agenda 1)))
1594 @end example
1596 It is important to call @code{update-agenda} periodically, otherwise
1597 no tasks will ever be run!
1599 In addition to using the global agenda, it is useful to have multiple
1600 agendas for different purposes. For example, the game world can use a
1601 different agenda than the user interface, so that pausing the game is
1602 a simple matter of not updating the world's agenda while continuing to
1603 update the user interface's agenda. The current agenda is dynamically
1604 scoped and can be changed using the @code{with-agenda} special form:
1606 @example
1607 (define game-world-agenda (make-agenda))
1609 (with-agenda game-world-agenda
1610 (at 60 (spawn-goblin))
1611 (at 120 (spawn-goblin))
1612 (at 240 (spawn-goblin-king)))
1613 @end example
1615 @deffn {Procedure} make-agenda
1616 Return a new task scheduler.
1617 @end deffn
1619 @deffn {Procedure} agenda? @var{obj}
1620 Return @code{#t} if @var{obj} is an agenda.
1621 @end deffn
1623 @deffn {Procedure} current-agenda
1624 @deffnx {Procedure} current-agenda @var{agenda}
1625 When called with no arguments, return the current agenda. When called
1626 with one argument, set the current agenda to @var{agenda}.
1627 @end deffn
1629 @deffn {Syntax} with-agenda @var{agenda} @var{body} @dots{}
1630 Evaluate @var{body} with the current agenda set to @var{agenda}.
1631 @end deffn
1633 @deffn {Procedure} agenda-time
1634 Return the current agenda time.
1635 @end deffn
1637 @deffn {Procedure} update-agenda @var{dt}
1638 Advance the current agenda by @var{dt}.
1639 @end deffn
1641 @deffn {Procedure} schedule-at @var{time} @var{thunk}
1642 Schedule @var{thunk}, a procedure of zero arguments, to be run at
1643 @var{time}.
1644 @end deffn
1646 @deffn {Procedure} schedule-after @var{delay} @var{thunk}
1647 Schedule @var{thunk}, a procedure of zero arguments, to be run after
1648 @var{delay}.
1649 @end deffn
1651 @deffn {Procedure} schedule-every @var{interval} @var{thunk} [@var{n}]
1652 Schedule @var{thunk}, a procedure of zero arguments, to be run every
1653 @var{interval} amount of time. Repeat this @var{n} times, or
1654 indefinitely if not specified.
1655 @end deffn
1657 @deffn {Syntax} at @var{time} @var{body} @dots{}
1658 Schedule @var{body} to be evaluated at @var{time}.
1659 @end deffn
1661 @deffn {Syntax} after @var{delay} @var{body} @dots{}
1662 Schedule @var{body} to be evaluated after @var{delay}.
1663 @end deffn
1665 @deffn {Syntax} every @var{interval} @var{body} @dots{}
1666 @deffnx {Syntax} every (@var{interval} @var{n}) @var{body} @dots{}
1667 Schedule @var{body} to be evaluated every @var{interval} amount of
1668 time. Repeat this @var{n} times, or indefinitely if not specified.
1669 @end deffn
1671 @node Scripts
1672 @subsection Scripts
1674 Now that we can schedule tasks, let's take things to the next level.
1675 It sure would be great if we could make procedures that described a
1676 series of actions that happened over time, especially if we could do
1677 so without contorting our code into a nest of callback procedures.
1678 This is where scripts come in. With scripts we can write code in a
1679 linear way, in a manner that appears to be synchronous, but with the
1680 ability to suspend periodically in order to let other scripts have a
1681 turn and prevent blocking the game loop. Building on top of the
1682 scheduling that agendas provide, here is a script that models a child
1683 trying to get their mother's attention:
1685 @example
1686 (script
1687 (while #t
1688 (display "mom!")
1689 (newline)
1690 (sleep 60))) ; where 60 = 1 second of real time
1691 @end example
1693 This code runs in an endless loop, but the @code{sleep} procedure
1694 suspends the script and schedules it to be run later by the agenda.
1695 So, after each iteration of the loop, control is returned back to the
1696 game loop and the program is not stuck spinning in a loop that will
1697 never exit. Pretty neat, eh?
1699 Scripts can suspend to any capable handler, not just the agenda.
1700 The @code{yield} procedure will suspend the current script and pass
1701 its ``continuation'' to a handler procedure. This handler procedure
1702 could do anything. Perhaps the handler stashes the continuation
1703 somewhere where it will be resumed when the user presses a specific
1704 key on the keyboard, or maybe it will be resumed when the player picks
1705 up an item off of the dungeon floor; the sky is the limit.
1707 Sometimes it is necessary to abruptly terminate a script after it has
1708 been started. For example, when an enemy is defeated their AI routine
1709 needs to be shut down. When a script is spawned, a handle to that
1710 script is returned that can be used to cancel it when desired.
1712 @example
1713 (define script (script (while #t (display "hey\n") (sleep 60))))
1714 ;; sometime later
1715 (cancel-script script)
1716 @end example
1718 @deffn {Procedure} spawn-script @var{thunk}
1719 Apply @var{thunk} as a script and return a handle to it.
1720 @end deffn
1722 @deffn {Syntax} script @var{body} @dots{}
1723 Evaluate @var{body} as a script and return a handle to it.
1724 @end deffn
1726 @deffn {Procedure} script? @var{obj}
1727 Return @code{#t} if @var{obj} is a script handle.
1728 @end deffn
1730 @deffn {Procedure} script-cancelled? @var{obj}
1731 Return @code{#t} if @var{obj} has been cancelled.
1732 @end deffn
1734 @deffn {Procedure} script-running? @var{obj}
1735 Return @code{#t} if @var{obj} has not yet terminated or been
1736 cancelled.
1737 @end deffn
1739 @deffn {Procedure} script-complete? @var{obj}
1740 Return @code{#t} if @var{obj} has terminated.
1741 @end deffn
1743 @deffn {Procedure} cancel-script @var{co}
1744 Prevent further execution of the script @var{co}.
1745 @end deffn
1747 @deffn {Procedure} yield @var{handler}
1748 Suspend the current script and pass its continuation to the
1749 procedure @var{handler}.
1750 @end deffn
1752 @deffn {Procedure} sleep @var{duration}
1753 Wait @var{duration} before resuming the current script.
1754 @end deffn
1756 @deffn {Procedure} channel-get @var{channel}
1757 Wait for a message from @var{channel}.
1758 @end deffn
1760 @deffn {Syntax} forever @var{body} @dots{}
1761 Evaluate @var{body} in an endless loop.
1762 @end deffn
1764 @node Tweening
1765 @subsection Tweening
1767 Tweening is the process of transitioning something from an initial
1768 state to a final state over a pre-determined period of time. In other
1769 words, tweening is a way to create animation. The @code{tween}
1770 procedure can be used within any script like so:
1772 @example
1773 (define x 0)
1774 (script
1775 ;; 0 to 100 in 60 ticks of the agenda.
1776 (tween 60 0 100 (lambda (y) (set! x y))))
1777 @end example
1779 @deffn {Procedure} tween @var{duration} @var{start} @var{end} @var{proc} [#:step 1 #:ease @code{smoothstep} #:interpolate @code{lerp}]
1780 Transition a value from @var{start} to @var{end} over @var{duration},
1781 sending each succesive value to @var{proc}. @var{step} controls the
1782 amount of time between each update of the animation.
1784 To control how the animation goes from the initial to final state, an
1785 ``easing'' procedure may be specified. By default, the
1786 @code{smoothstep} easing is used, which is a more pleasing default
1787 than a simplistic linear function. @xref{Easings} for a complete list
1788 of available easing procedures.
1790 The @var{interpolate} procedure computes the values in between
1791 @var{start} and @var{end}. By default, linear interpolation (``lerp''
1792 for short) is used.
1793 @end deffn
1795 @node Channels
1796 @subsection Channels
1798 Channels are a tool for communicating amongst different scripts. One
1799 script can write a value to the channel and another can read from it.
1800 Reading or writing to a channel suspends that script until there is
1801 someone on the other end of the line to complete the transaction.
1803 Here's a simplistic example:
1805 @example
1806 (define c (make-channel))
1808 (script
1809 (forever
1810 (let ((item (channel-get c)))
1811 (pk 'got item))))
1813 (script
1814 (channel-put c 'sword)
1815 (channel-put c 'shield)
1816 (channel-put c 'potion))
1817 @end example
1819 @deffn {Procedure} make-channel
1820 Return a new channel
1821 @end deffn
1823 @deffn {Procedure} channel? @var{obj}
1824 Return @code{#t} if @var{obj} is a channel.
1825 @end deffn
1827 @deffn {Procedure} channel-get @var{channel}
1828 Retrieve a value from @var{channel}. The current script suspends
1829 until a value is available.
1830 @end deffn
1832 @deffn {Procedure} channel-put @var{channel} @var{data}
1833 Send @var{data} to @var{channel}. The current script suspends until
1834 another script is available to retrieve the value.
1835 @end deffn