doc: Rename "Blending and Depth Testing" section to just "Blending".
[chickadee.git] / doc / api.texi
CommitLineData
ee2cc0b4
DT
1@menu
2* Kernel:: The fundamental components.
e69ff99c 3* Math:: Linear algebra, spatial partitioning, and more.
ee2cc0b4 4* Graphics:: Eye candy.
6a182194 5* Scripting:: Bringing the game world to life.
ee2cc0b4
DT
6@end menu
7
8@node Kernel
9@section Kernel
10
11At the very core of Chickadee, in the @code{(chickadee)} module, lies
92ddc07c
DT
12an event loop. This loop, or ``kernel'', is responsible for ensuring
13that the game is updated at the desired interval, rendering the
14current state of the game world, and handling errors if they occur.
ee2cc0b4
DT
15The kernel implements what is known as a ``fixed timestep'' game loop,
16meaning that the game simulation will be advanced by a fixed interval
17of time and will never vary from frame to frame, unlike some other
18styles of game loops. The appropriately named @code{run-game} and
19@code{abort-game} procedures are the entry and exit points to the
92ddc07c 20Chickadee game loop kernel.
ee2cc0b4
DT
21
22On its own, the kernel does not do very much at all. In order to
92ddc07c
DT
23actually respond to input events, update game state, or render output,
24the programmer must provide an engine. But don’t worry, you don’t
25have to start from scratch! Chickadee comes with a simple engine that
26uses SDL to create a graphical window and handle input devices, and
27OpenGL to handle rendering. This default engine is enough for most
28users to get started writing games quickly. More advanced users may
29want to write a custom engine that uses a different I/O system.
30Perhaps you are writing a text adventure or roguelike that reads from
31and writes to a terminal instead of a graphical window. The game loop
32kernel makes no assumptions.
33
34@deffn {Procedure} run-game [#:update] [#:render] [#:time] [#:error] @
ee2cc0b4 35 [#:update-hz 60]
6306a7dc 36
92ddc07c 37Start the game loop. This procedure will not return until
ee2cc0b4
DT
38@code{abort-game} is called.
39
92ddc07c
DT
40The core game loop is generic and requires four additional procedures
41to operate:
ee2cc0b4 42
92ddc07c
DT
43@itemize
44@item
45@var{update}: Called @var{update-hz} times per second to advance the
46game simulation. This procedure is called with a single argument: The
47amount 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
50the desired output device. This procedure is called with a single
51argument: A value in the range [0, 1] which represents how much time
52has past since the last game state update relative to the upcoming
53game state update, as a percentage. Because the game state is updated
54independent of rendering, it is often the case that rendering is
55occuring between two updates. If the game is rendered as it was
56during the last update, a strange side-effect will occur that makes
57animation appear rough or ``choppy''. To counter this, the
58@var{alpha} value can be used to perfrom a linear interpolation of a
59moving object between its current position and its previous position.
60This odd trick has the pleasing result of making the animation look
61smooth again, but requires keeping track of previous state.
62@item
63@var{time}: Called to get the current time in milliseconds. This
64procedure 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
68called with three arguments: The call stack, the error key, and the
69error arguments. If no error handler is provided, the default
70behavior is to simply re-throw the error.
71@end itemize
ee2cc0b4 72
ee2cc0b4
DT
73@end deffn
74
92ddc07c
DT
75@deffn {Procedure} abort-game
76Stop the currently running Chickadee game loop.
ee2cc0b4
DT
77@end deffn
78
92ddc07c
DT
79Since most users will want to write 2D/3D games with hardware
80accelerated graphics rendering, controlled via keyboard, mouse, or
81game controller, Chickadee comes with an easy to use engine just for
82this purpose in the @code{(chickadee sdl)} module:
83@code{run-game/sdl}.
ee2cc0b4 84
92ddc07c
DT
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]
ee2cc0b4 93
92ddc07c 94Run the Chickadee game loop using the SDL engine.
ee2cc0b4 95
92ddc07c
DT
96A new graphical window will be opened with @var{window-width} x
97@var{window-height} as its dimensions, @var{window-title} as its
98title, and in fullscreen mode if @var{window-fullscreen?} is
99@code{#t}.
ee2cc0b4 100
92ddc07c
DT
101@itemize
102@item
103@var{load}: Called with zero arguments when the game window has opened
104but before the game loop has started. Can be used to perform
105initialization that requires an open window and OpenGL context such as
106loading textures.
ee2cc0b4 107
92ddc07c
DT
108@item
109@var{update}: Called @var{update-hz} times per second with one
110argument: The amount of time to advance the game simulation.
d9350935 111
92ddc07c
DT
112@item
113@var{draw}: Called each time a frame should be rendered with a single
114argument known as the @code{alpha} value. See the documentation for
115@code{run-game} for an explanation of this value.
d9350935 116
92ddc07c
DT
117@item
118@var{quit}: Called with zero arguments when the user tries to close
119the game window. The default behavior is to exit the game.
d9350935 120
92ddc07c
DT
121@item
122@var{key-press}: Called with four arguments when a key is pressed on
123the keyboard:
d9350935
DT
124
125@enumerate
126@item
127@var{key}: The symbolic name of the ``virtual'' key that was pressed.
128For example: @code{backspace}. It's called a virtual key because the
129operating system may map a physical keyboard key to another key
92ddc07c
DT
130entirely, such as how the author likes to bind the ``caps lock'' key
131to mean ``control''.
d9350935
DT
132
133@item
134@var{scancode}: The symbolic name of the physical key that was
135pressed.
136
137@item
138@var{modifiers}: A list of the symbolic names of modifier keys that
139were being held down when the key was pressed. Possible values
140include @code{ctrl}, @code{alt}, and @code{shift}.
141
142@item
143@var{repeat?}: @code{#t} if this is a repeated press of the same key.
144
145@end enumerate
146
92ddc07c
DT
147@item
148@var{key-release}: Called with three arguments when a key is released
149on the keyboard:
d9350935
DT
150
151@enumerate
152@item
153@var{key}: The symbolic name of the ``virtual'' key that was released.
154
155@item
156@var{scancode}: The symbolic name of the physical key that was
157released.
158
159@item
160@var{modifiers}: A list of the symbolic names of modifier keys that
161were being held down when the key was released.
162
163@end enumerate
164
92ddc07c
DT
165@item
166@var{text-input}: Called with a single argument, a string of text,
167when printable text is typed on the keyboard.
44ba82ba 168
92ddc07c
DT
169@item
170@var{mouse-press}: Called with four arguments when a mouse button is
171pressed:
44ba82ba
DT
172@enumerate
173
174@item
175@var{button}: The symbolic name of the button that was pressed, such
176as @code{left}, @code{middle}, or @code{right}.
177
178@item
179@var{clicks}: The number of times the button has been clicked in a row.
180
181@item
182@var{x}: The x coordinate of the mouse cursor.
183
184@item
185@var{y}: The y coordinate of the mouse cursor.
186
187@end enumerate
188
92ddc07c
DT
189@item
190@var{mouse-release}: Called with three arguments when a mouse button
191is released:
44ba82ba
DT
192
193@enumerate
194
195@item
196@var{button}: The symbolic name of the button that was released.
197
198@item
199@var{x}: The x coordinate of the mouse cursor.
200
201@item
202@var{y}: The y coordinate of the mouse cursor.
203
204@end enumerate
205
92ddc07c
DT
206@item
207@var{mouse-move}: Called with five arguments when the mouse is moved:
44ba82ba
DT
208
209@enumerate
210
211@item
212@var{x}: The x coordinate of the mouse cursor.
213
214@item
215@var{y}: The y coordinate of the mouse cursor.
216
217@item
218@var{dx}: The amount the mouse has moved along the x axis since the
219last mouse move event.
220
221@item
222@var{dy}: The amount the mouse has moved along the y axis since the
223last mouse move event.
224
225@item
226@var{buttons}: A list of the buttons that were pressed down when the
227mouse was moved.
228
229@end enumerate
230
92ddc07c
DT
231@item
232@var{controller-add}: Called with a single argument, an SDL game
233controller object, when a game controller is connected.
d9350935 234
92ddc07c
DT
235@item
236@var{controller-remove}: Called with a single argument, an SDL game
237controller object, when a game controller is disconnected.
d9350935 238
92ddc07c
DT
239@item
240@var{controller-press}: Called with two arguments when a button on a
241game controller is pressed:
44ba82ba
DT
242
243@enumerate
244
245@item
246@var{controller}: The controller that triggered the event.
247
248@item
249@var{button}: The symbolic name of the button that was pressed.
250Possible buttons are:
251
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}
283
284@end itemize
285
286@end enumerate
287
92ddc07c
DT
288@item
289@var{controller-release}: Called with two arguments when a button on a
290game controller is released:
44ba82ba
DT
291
292@enumerate
293
294@item
295@var{controller}: The controller that triggered the event.
296
297@item
298@var{button}: The symbolic name of the button that was released.
299
300@end enumerate
301
92ddc07c
DT
302@item
303@var{controller-move}: Called with three arguments when an analog
304stick or trigger on a game controller is moved:
44ba82ba
DT
305
306@enumerate
307
308@item
309@var{controller}: The controller that triggered the event.
310
311@item
312@var{axis}: The symbolic name of the axis that was moved. Possible
313values are:
314
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
329
330@end enumerate
331
92ddc07c
DT
332@item
333@var{error}: Called with three arguments when an error occurs:
d9350935 334
92ddc07c 335@enumerate
ee2cc0b4 336
92ddc07c
DT
337@item
338@var{stack}: The call stack at the point of error.
6d78be95 339
92ddc07c
DT
340@item
341@var{key}: The exception key.
6d78be95 342
92ddc07c
DT
343@item
344@var{args}: The arguments thrown with the exception.
6d78be95 345
92ddc07c
DT
346@end enumerate
347
348The default behavior is to re-throw the error.
349
350@end itemize
6d78be95 351
6d78be95
DT
352@end deffn
353
ee2cc0b4
DT
354@node Math
355@section Math
356
d9350935
DT
357Chickadee contains data types and procedures for performing the most
358common computations in video game simulations such as linear algebra
359with vectors and matrices and axis-aligned bounding box collision
360detection.
361
362@menu
78a0e2a2 363* Basics:: Commonly used, miscellaneous things.
d9350935 364* Vectors:: Euclidean vectors.
d9350935 365* Rectangles:: Axis-aligned bounding boxes.
7955ab53 366* Grid:: Spatial partitioning for bounding boxes.
5bdd6bc0
DT
367* Matrices:: Transformation matrices.
368* Quaternions:: Rotations about an arbitrary axis.
dd8cf461 369* Easings:: Easing functions for interesting animations.
8f21fe16 370* Bezier Curves:: Cubic Bezier curves and paths in 2D space.
e69ff99c 371* Path Finding:: Generic A* path finding.
d9350935
DT
372@end menu
373
78a0e2a2
DT
374@node Basics
375@subsection Basics
376
4fa48196 377@defvar pi
78a0e2a2
DT
378An essential constant for all trigonometry. @code{@U{03C0}} is the ratio
379of a circle's circumferences to its diameter. Since @code{@U{03C0}} is an
380irrational number, the @var{pi} in Chickadee is a mere floating point
381approximation that is ``good enough.''
382@end defvar
383
4fa48196 384@defvar pi/2
78a0e2a2
DT
385Half of @var{pi}.
386@end defvar
387
5e5c0ac2
DT
388@deffn {Procedure} cotan @var{z}
389Return the cotangent of @var{z}.
390@end deffn
391
d9350935
DT
392@node Vectors
393@subsection Vectors
394
c8a84e81
DT
395Unlike Scheme's vector data type, which is a sequence of arbitrary
396Scheme objects, Chickadee's @code{(chickadee math vector)} module
397provides vectors in the linear algebra sense: Sequences of numbers
398specialized for particular coordinate spaces. As of now, Chickadee
399provides 2D and 3D vectors, with 4D vector support coming in a future
400release.
401
402Here's a quick example of adding two vectors:
403
404@example
405(define v (vec2+ (vec2 1 2) (vec2 3 4)))
406@end example
407
408Since vectors are used so frequently, the reader macro @code{#v} is
409used to cut down on typing:
410
411@example
412(define v (vec2+ #v(1 2) #v(3 4)))
413@end example
414
415@subsubsection A Note About Performance
416
417A lot of time has been spent making Chickadee's vector operations
418perform relatively efficiently in critical code paths where excessive
419garbage generation will cause major performance issues. The general
420rule is that procedures ending with @code{!} perform an in-place
421modification of one of the arguments in order to avoid allocating a
422new vector. These procedures are also inlined by Guile's compiler in
423order to take advantage of optimizations relating to floating point
424math operations. The downside is that since these are not pure
425functions, they do not compose well and create more verbose code.
426
427@subsubsection 2D Vectors
428
429@deffn {Procedure} vec2 @var{x} @var{y}
430Return a new 2D vector with coordinates (@var{x}, @var{y}).
431@end deffn
432
433@deffn {Procedure} vec2/polar @var{r} @var{theta}
434Return a new 2D vector containing the Cartesian representation of the
435polar coordinate (@var{r}, @var{theta}). The angle @var{theta} is
436measured in radians.
437@end deffn
438
439@deffn {Procedure} vec2? @var{obj}
440Return @code{#t} if @var{obj} is a 2D vector.
441@end deffn
442
443@deffn {Procedure} vec2-x @var{v}
444Return the X coordinate of the 2D vector @var{v}.
445@end deffn
446
447@deffn {Procedure} vec2-y @var{v}
448Return the Y coordinate of the 2D vector @var{v}.
449@end deffn
450
451@deffn {Procedure} vec2-copy @var{v}
452Return a fresh copy of the 2D vector @var{v}.
453@end deffn
454
455@deffn {Procedure} vec2-magnitude @var{v}
456Return the magnitude of the 2D vector @var{v}.
457@end deffn
458
459@deffn {Procedure} vec2-dot-product @var{v1} @var{v2}
460Return the dot product of the 2D vectors @var{v1} and @var{v2}.
461@end deffn
462
463@deffn {Procedure} vec2-normalize @var{v}
464Return the normalized form of the 2D vector @var{v}.
465@end deffn
466
467@deffn {Procedure} vec2+ @var{v} @var{x}
468Add @var{x}, either a 2D vector or a scalar (i.e. a real number), to
469the 2D vector @var{v} and return a new vector containing the sum.
470@end deffn
471
472@deffn {Procedure} vec2- @var{v} @var{x}
473Subtract @var{x}, either a 2D vector or a scalar, from the 2D vector
474@var{v} and return a new vector containing the difference.
475@end deffn
476
477@deffn {Procedure} vec2* @var{v} @var{x}
478Multiply the 2D vector @var{v} by @var{x}, a 2D vector or a scalar,
479and return a new vector containing the product.
480@end deffn
481
482@deffn {Procedure} set-vec2-x! @var{v} @var{x}
483Set the X coordinate of the 2D vector @var{v} to @var{x}.
484@end deffn
485
486@deffn {Procedure} set-vec2-y! @var{v} @var{y}
487Set the Y coordinate of the 2D vector @var{v} to @var{y}.
488@end deffn
489
490@deffn {Procedure} vec2-copy! @var{source} @var{target}
491Copy the 2D vector @var{source} into the 2D vector @var{target}.
492@end deffn
493
494@deffn {Procedure} vec2-add! @var{v} @var{x}
495Perform an in-place modification of the 2D vector @var{v} by adding
496@var{x}, a 2D vector or a scalar.
497@end deffn
498
499@deffn {Procedure} vec2-sub! @var{v} @var{x}
500Perform an in-place modification of the 2D vector @var{v} by
501subtracting @var{x}, a 2D vector or a scalar.
502@end deffn
503
504@deffn {Procedure} vec2-mult! @var{v} @var{x}
505Perform an in-place modification of the 2D vector @var{v} by
506multiplying it by @var{x}, a 2D vector or a scalar.
507@end deffn
508
509@subsubsection 3D Vectors
510
511@deffn {Procedure} vec3 @var{x} @var{y}
512Return a new 2D vector with coordinates (@var{x}, @var{y}).
513@end deffn
514
515@deffn {Procedure} vec3? @var{obj}
516Return @code{#t} if @var{obj} is a 3D vector.
517@end deffn
518
519@deffn {Procedure} vec3-x @var{v}
520Return the X coordinate of the 3D vector @var{v}.
521@end deffn
522
523@deffn {Procedure} vec3-y @var{v}
524Return the Y coordinate of the 3D vector @var{v}.
525@end deffn
526
527@deffn {Procedure} vec3-z @var{v}
528Return the Z coordinate of the 3D vector @var{v}.
529@end deffn
530
531@deffn {Procedure} vec3-copy @var{v}
532Return a fresh copy of the 3D vector @var{v}.
533@end deffn
534
535@deffn {Procedure} vec3-magnitude @var{v}
536Return the magnitude of the 3D vector @var{v}.
537@end deffn
538
539@deffn {Procedure} vec3-dot-product @var{v1} @var{v2}
540Return the dot product of the 3D vectors @var{v1} and @var{v2}.
541@end deffn
542
543@deffn {Procedure} vec3-normalize @var{v}
544Return the normalized form of the 3D vector @var{v}.
545@end deffn
546
547@deffn {Procedure} vec3+ @var{v} @var{x}
548Add @var{x}, either a 3D vector or a scalar (i.e. a real number), to
549the 3D vector @var{v} and return a new vector containing the sum.
550@end deffn
551
552@deffn {Procedure} vec3- @var{v} @var{x}
553Subtract @var{x}, either a 3D vector or a scalar, from the 3D vector
554@var{v} and return a new vector containing the difference.
555@end deffn
556
557@deffn {Procedure} vec3* @var{v} @var{x}
558Multiply the 3D vector @var{v} by @var{x}, a 3D vector or a scalar,
559and return a new vector containing the product.
560@end deffn
561
562@deffn {Procedure} set-vec3-x! @var{v} @var{x}
563Set the X coordinate of the 3D vector @var{v} to @var{x}.
564@end deffn
565
566@deffn {Procedure} set-vec3-y! @var{v} @var{y}
567Set the Y coordinate of the 3D vector @var{v} to @var{y}.
568@end deffn
569
570@deffn {Procedure} set-vec3-z! @var{v} @var{z}
571Set the Z coordinate of the 3D vector @var{v} to @var{z}.
572@end deffn
573
574@deffn {Procedure} vec3-copy! @var{source} @var{target}
575Copy the 3D vector @var{source} into the 3D vector @var{target}.
576@end deffn
577
578@deffn {Procedure} vec3-add! @var{v} @var{x}
579Perform an in-place modification of the 3D vector @var{v} by adding
580@var{x}, a 3D vector or a scalar.
581@end deffn
582
583@deffn {Procedure} vec3-sub! @var{v} @var{x}
584Perform an in-place modification of the 3D vector @var{v} by
585subtracting @var{x}, a 3D vector or a scalar.
586@end deffn
587
588@deffn {Procedure} vec3-mult! @var{v} @var{x}
589Perform an in-place modification of the 3D vector @var{v} by
590multiplying it by @var{x}, a 3D vector or a scalar.
591@end deffn
592
5bdd6bc0
DT
593@node Rectangles
594@subsection Rectangles
595
596The @code{(chickadee math rect)} module provides an API for
597manipulating axis-aligned bounding boxes (AABBs). AABBs are often
598used for collision detection in games. Common use-cases are defining
599``hitboxes'' in platformers or using them for the ``broad phase'' of a
600collision detection algorithm that uses a more complex (and thus
601slower) method of determining the actual collisions.
602
603Like some of the other math modules, there exists a collection of
604functions that do in-place modification of rectangles for use in
605performance critical code paths.
606
607@deffn {Procedure} make-rect @var{x} @var{y} @var{width} @var{height}
608Create a new rectangle that is @var{width} by @var{height} in size and
609whose bottom-left corner is located at (@var{x}, @var{y}).
610@end deffn
611
612@deffn {Procedure} rect? @var{obj}
613Return @code{#t} if @var{obj} is a rectangle.
614@end deffn
615
616@deffn {Procedure} rect-within? @var{rect1} @var{rect2}
617Return @code{#t} if @var{rect2} is completely within @var{rect1}.
618@end deffn
619
620@deffn {Procedure} rect-intersects? @var{rect1} @var{rect2}
621Return @code{#t} if @var{rect2} overlaps @var{rect1}.
622@end deffn
623
624@deffn {Procedure} rect-contains? @var{rect} @var{x} @var{y}
625Return @code{#t} if the coordinates (@var{x}, @var{y}) are within
626@var{rect}.
627@end deffn
628
629@deffn {Procedure} rect-contains-vec2? @var{rect} @var{v}
630Return @code{#t} if the 2D vector @var{v} is within the bounds of
631@var{rect}.
632@end deffn
633
634@deffn {Procedure} rect-x @var{rect}
635Return the X coordinate of the lower-left corner of @var{rect}.
636@end deffn
637
638@deffn {Procedure} rect-y @var{rect}
639Return the Y coordinate of the lower-left corner of @var{rect}.
640@end deffn
641
642@deffn {Procedure} rect-left @var{rect}
643Return the left-most X coordinate of @var{rect}.
644@end deffn
645
646@deffn {Procedure} rect-right @var{rect}
647Return the right-most X coordinate of @var{rect}.
648@end deffn
649
650@deffn {Procedure} rect-bottom @var{rect}
651Return the bottom-most Y coordinate of @var{rect}.
652@end deffn
653
654@deffn {Procedure} rect-top @var{rect}
655Return the top-most Y coordinate of @var{rect}.
656@end deffn
657
658@deffn {Procedure} rect-center-x @var{rect}
659Return the X coordinate of the center of @var{rect}.
660@end deffn
661
662@deffn {Procedure} rect-center-y @var{rect}
663Return the Y coordinate of the center of @var{rect}.
664@end deffn
665
666@deffn {Procedure} rect-width @var{rect}
667Return the width of @var{rect}.
668@end deffn
669
670@deffn {Procedure} rect-height @var{rect}
671Return the height of @var{rect}.
672@end deffn
673
674@deffn {Procedure} rect-area @var{rect}
675Return the surface area covered by @var{rect}.
676@end deffn
677
678@deffn {Procedure} rect-clamp-x @var{rect} @var{x}
679Restrict @var{x} to the portion of the X axis covered by @var{rect}.
680@end deffn
681
682@deffn {Procedure} rect-clamp-y @var{rect} @var{y}
683Restrict @var{y} to the portion of the Y axis covered by @var{rect}.
684@end deffn
685
686@deffn {Procedure} rect-clamp @var{rect1} @var{rect2}
687Return a new rect that adjusts the location of @var{rect1} so that it
688is completely within @var{rect2}. An exception is thrown in the case
689that @var{rect1} cannot fit completely within @var{rect2}.
690@end deffn
691
692@deffn {Procedure} rect-move @var{rect} @var{x} @var{y}
693Return a new rectangle based on @var{rect} but moved to the
694coordinates (@var{x}, @var{y}).
695@end deffn
696
697@deffn {Procedure} rect-move-vec2 @var{rect} @var{v}
698Return a new rectangle based on @var{rect} but moved to the
699coordinates in the 2D vector @var{v}.
700@end deffn
701
702@deffn {Procedure} rect-move-by @var{rect} @var{x} @var{y}
703Return a new rectangle based on @var{rect} but moved by (@var{x},
704@var{y}) units relative to its current location.
705@end deffn
706
707@deffn {Procedure} rect-move-by-vec2 @var{rect} @var{v}
708Return a new rectangle based on @var{rect} but moved by the 2D vector
709@var{v} relative to its current location.
710@end deffn
711
712@deffn {Procedure} rect-inflate @var{rect} @var{width} @var{height}
713Return a new rectangle based on @var{rect}, but expanded by
714@var{width} units on the X axis and @var{height} units on the Y axis,
715while keeping the rectangle centered on the same point.
716@end deffn
717
718@deffn {Procedure} rect-union @var{rect1} @var{rect2}
719Return a new rectangle that completely covers the area of @var{rect1}
720and @var{rect2}.
721@end deffn
722
723@deffn {Procedure} rect-clip @var{rect1} @var{rect2}
724Return a new rectangle that is the overlapping region of @var{rect1}
725and @var{rect2}. If the two rectangles do not overlap, a rectangle of
7260 width and 0 height is returned.
727@end deffn
728
729@deffn {Procedure} set-rect-x! @var{rect} @var{x}
730Set the left X coordinate of @var{rect} to @var{x}.
731@end deffn
732
733@deffn {Procedure} set-rect-y! @var{rect} @var{y}
734Set the bottom Y coordinate of @var{rect} to @var{y}.
735@end deffn
736
737@deffn {Procedure} set-rect-width! @var{rect} @var{width}
738Set the width of @var{rect} to @var{width}.
739@end deffn
740
741@deffn {Procedure} set-rect-height! @var{rect} @var{height}
742Set the height of @var{rect} to @var{height}.
743@end deffn
744
745@deffn {Procedure} rect-move! @var{rect} @var{x} @var{y}
746Move @var{rect} to (@var{x}, @var{y}) in-place.
747@end deffn
748
749@deffn {Procedure} rect-move-vec2! @var{rect} @var{v}
750Move @var{rect} to the 2D vector @var{v} in-place.
751@end deffn
752
753@deffn {Procedure} rect-move-by! @var{rect} @var{x} @var{y}
754Move @var{rect} by (@var{x}, @var{y}) in-place.
755@end deffn
756
757@deffn {Procedure} rect-move-by-vec2! @var{rect} @var{v}
758Move @var{rect} by the 2D vector @var{v} in-place.
759@end deffn
760
761@deffn {Procedure} rect-inflate! @var{rect} @var{width} @var{height}
762Expand @var{rect} by @var{width} and @var{height} in-place.
763@end deffn
764
765@deffn {Procedure} rect-union! @var{rect1} @var{rect2}
766Modify @var{rect1} in-place to completely cover the area of both
767@var{rect1} and @var{rect2}.
768@end deffn
769
770@deffn {Procedure} rect-clip! @var{rect1} @var{rect2}
771Modify @var{rect1} in-place to be the overlapping region of
772@var{rect1} and @var{rect2}.
773@end deffn
774
775@deffn {Procedure} rect-clamp! @var{rect1} @var{rect2}
776Adjust the location of @var{rect1} in-place so that its bounds are
777completely within @var{rect2}. An exception is thrown in the case
778that @var{rect1} cannot fit completely within @var{rect2}.
779@end deffn
780
781@deffn {Procedure} vec2-clamp-to-rect! @var{v} @var{rect}
782Restrict the coordinates of the 2D vector @var{v} so that they are
783within the bounds of @var{rect}. @var{v} is modified in-place.
784@end deffn
785
7955ab53
DT
786@node Grid
787@subsection Grid
788
789The @code{(chickadee math grid)} module provides a simple spatial
790partitioning system for axis-aligned bounding boxes
791(@pxref{Rectangles}) in 2D space. The grid divides the world into
792tiles and keeps track of which rectangles occupy which tiles. When
793there are lots of moving objects in the game world that need collision
794detection, the grid greatly speeds up the process. Instead of
795checking collisions of each object against every other object (an
796O(n^2) operation), the grid quickly narrows down which objects could
797possibly be colliding and only performs collision testing against a
798small set of objects.
799
800In addition to checking for collisions, the grid also handles the
801resolution of collisions. Exactly how each collision is resolved is
802user-defined. A player bumping into a wall may slide against it. An
803enemy colliding with a projectile shot by the player may get pushed
804back in the opposite direction. Two players colliding may not need
805resolution at all and will just pass through each other. The way this
806works is that each time an object (A) is moved within the grid, the
807grid looks for an object (B) that may possibly be colliding with A. A
808user-defined procedure known as a ``filter'' is then called with both
809A and B. If the filter returns @code{#f}, it means that even if A and
810B are colliding, no collision resolution is needed. In this case the
811grid won't waste time checking if they really do collide because it
812doesn't matter. If A and B are collidable, then the filter returns a
813procedure that implements the resolution technique. The grid will
814then perform a collision test. If A and B are colliding, the resolver
815procedure is called. It's the resolvers job to adjust the objects
816such that they are no longer colliding. The grid module comes with a
817very simple resolution procedure, @code{slide}, that adjusts object A
818by the smallest amount so that it no longer overlaps with B. By using
819this filtering technique, a game can resolve collisions between
820different objects in different ways.
821
822@deffn {Procedure} make-grid [@var{cell-size} 64]
823Return a new grid partitioned into @var{cell-size} tiles.
824@end deffn
825
826@deffn {Procedure} grid? @var{obj}
827Return @code{#t} if @var{obj} is a grid.
828@end deffn
829
830@deffn {Procedure} cell? @var{obj}
831Return @code{#t} if @var{obj} is a grid cell.
832@end deffn
833
834@deffn {Procedure} cell-count @var{cell}
835Return the number of items in @var{cell}.
836@end deffn
837
838@deffn {Procedure} grid-cell-size @var{grid}
839Return the cell size of @var{grid}.
840@end deffn
841
842@deffn {Procedure} grid-cell-count @var{grid}
843Return the number of cells currently in @var{grid}.
844@end deffn
845
846@deffn {Procedure} grid-item-count @var{grid}
847Return the number of items in @var{grid}.
848@end deffn
849
850@deffn {Procedure} grid-add @var{grid} @var{item} @var{x} @var{y} @
851 @var{width} @var{height}
852
853Add @var{item} to @var{grid} represented by the axis-aligned bounding
854box whose lower-left corner is at (@var{x}, @var{y}) and is
855@var{width} x @var{height} in size.
856@end deffn
857
858@deffn {Procedure} grid-remove @var{grid} @var{item}
859Return @var{item} from @var{grid}.
860@end deffn
861
862@deffn {Procedure} grid-clear @var{grid}
863Remove all items from @var{grid}.
864@end deffn
865
866@deffn {Procedure} grid-move @var{grid} @var{item} @var{position} @var{filter}
867Attempt to move @var{item} in @var{grid} to @var{position} (a 2D
868vector) and check for collisions. For each collision, @var{filter}
869will be called with two arguments: @var{item} and the item it collided
870with. If a collision occurs, @var{position} may be modified to
871resolve the colliding objects.
872@end deffn
873
874@deffn {Procedure} for-each-cell @var{proc} @var{grid} [@var{rect}]
875Call @var{proc} with each cell in @var{grid} that intersects
876@var{rect}, or every cell if @var{rect} is @code{#f}.
877@end deffn
878
879@deffn {Procedure} for-each-item @var{proc} @var{grid}
880Call @var{proc} for each item in @var{grid}.
881@end deffn
882
883@deffn {Procedure} slide @var{item} @var{item-rect} @
884 @var{other} @var{other-rect} @var{goal}
885
886Resolve the collision that occurs between @var{item} and @var{other}
887when moving @var{item-rect} to @var{goal} by sliding @var{item-rect}
888the minimum amount needed to make it no longer overlap
889@var{other-rect}.
890@end deffn
891
d9350935
DT
892@node Matrices
893@subsection Matrices
894
c8a84e81
DT
895The @code{(chickadee math matrix)} module provides an interface for
896working with the most common type of matrices in game development: 4x4
897transformation matrices.
898
899@subsubsection Another Note About Performance
900
901Much like the vector API, the matrix API is commonly used in
902performance critical code paths. In order to reduce the amount of
903garbage generated and improve matrix multiplication performance, there
904are many procedures that perform in-place modifications of matrix
905objects.
906
907@subsubsection Matrix Operations
908
909@deffn {Procedure} make-matrix4 @var{aa} @var{ab} @var{ac} @var{ad} @
910 @var{ba} @var{bb} @var{bc} @var{bd} @
911 @var{ca} @var{cb} @var{cc} @var{cd} @
912 @var{da} @var{db} @var{dc} @var{dd}
913
914Return a new 4x4 matrix initialized with the given 16 values in
915column-major format.
916@end deffn
917
918@deffn {Procedure} make-null-matrix4
919Return a new 4x4 matrix with all values initialized to 0.
920@end deffn
921
922@deffn {Procedure} make-identity-matrix4
923Return a new 4x4 identity matrix. Any matrix multiplied by the
924identity matrix yields the original matrix. This procedure is
925equivalent to the following code:
926
927@example
928(make-matrix4 1 0 0 0
929 0 1 0 0
930 0 0 1 0
931 0 0 0 1)
932@end example
933
934@end deffn
935
936@deffn {Procedure} matrix4? @var{obj}
937Return @code{#t} if @var{obj} is a 4x4 matrix.
938@end deffn
939
940@deffn {Procedure} matrix4* . @var{matrices}
941Return a new 4x4 matrix containing the product of multiplying all of
942the given @var{matrices}.
943
944Note: Remember that matrix multiplication is @strong{not} commutative!
945@end deffn
946
947@deffn {Procedure} orthographic-projection @var{left} @var{right} @
948 @var{top} @var{bottom} @
949 @var{near} @var{far}
950
951Return a new 4x4 matrix that represents an orthographic (2D)
952projection for the horizontal clipping plane @var{top} and
953@var{bottom}, the vertical clipping plane @var{top} and @var{bottom},
954and the depth clipping plane @var{near} and @var{far}.
955@end deffn
956
957@deffn {Procedure} perspective-projection @var{fov} @
958 @var{aspect-ratio} @
959 @var{near} @var{far}
960
961Return a new 4x4 matrix that represents a perspective (3D) projection
962with a field of vision of @var{fov} radians, an aspect ratio of
963@var{aspect-ratio}, and a depth clipping plane defined by @var{near}
964and @var{far}.
965@end deffn
966
967@deffn {Procedure} matrix4-translate @var{x}
968Return a new 4x4 matrix that represents a translation by @var{x}, a 2D
969vector, a 3D vector, or a rectangle (in which case the bottom-left
970corner of the rectangle is used).
971@end deffn
972
973@deffn {Procedure} matrix4-scale @var{s}
974Return a new 4x4 matrix that represents a scaling along the X, Y, and
975Z axes by the scaling factor @var{s}, a real number.
976@end deffn
977
978@deffn {Procedure} matrix4-rotate @var{q}
979Return a new 4x4 matrix that represents a rotation about an arbitrary
980axis defined by the quaternion @var{q}.
981@end deffn
982
983@deffn {Procedure} matrix4-rotate-z @var{theta}
984Return a new 4x4 matrix that represents a rotation about the Z axis by
985@var{theta} radians.
986@end deffn
987
988@deffn {Procedure} matrix4-identity! @var{matrix}
989Modify @var{matrix} in-place to contain the identity matrix.
990@end deffn
991
992@deffn {Procedure} matrix4-mult! @var{dest} @var{a} @var{b}
993Multiply the 4x4 matrix @var{a} by the 4x4 matrix @var{b} and store
994the result in the 4x4 matrix @var{dest}.
995@end deffn
996
997@deffn {Procedure} matrix4-translate! @var{matrix} @var{x}
998Modify @var{matrix} in-place to contain a translation by @var{x}, a 2D
999vector, a 3D vector, or a rectangle (in which case the bottom-left
1000corner of the rectangle is used).
1001@end deffn
1002
1003@deffn {Procedure} matrix4-scale! @var{matrix} @var{s}
1004Modify @var{matrix} in-place to contain a scaling along the X, Y, and
1005Z axes by the scaling factor @var{s}, a real number.
1006@end deffn
1007
1008@deffn {Procedure} matrix4-rotate! @var{matrix} @var{q}
1009Modify @var{matrix} in-place to contain a rotation about an arbitrary
1010axis defined by the quaternion @var{q}.
1011@end deffn
1012
1013@deffn {Procedure} matrix4-rotate-z! @var{matrix} @var{theta}
1014Modify @var{matrix} in-place to contain a rotation about the Z axis by
1015@var{theta} radians.
1016@end deffn
1017
1018@deffn {Procedure} matrix4-2d-transform! @var{matrix} [#:origin] @
1019 [#:position] [#:rotation] @
1020 [#:scale] [#:skew]
1021
1022Modify @var{matrix} in-place to contain the transformation described
1023by @var{position}, a 2D vector or rectangle, @var{rotation}, a scalar
1024representing a rotation about the Z axis, @var{scale}, a 2D vector,
1025and @var{skew}, a 2D vector. The transformation happens with respect
1026to @var{origin}, a 2D vector. If an argument is not provided, that
1027particular transformation will not be included in the result.
1028@end deffn
1029
1030@deffn {Procedure} transform! @var{matrix} @var{v}
1031Modify the 2D vector @var{v} in-place by multiplying it by the 4x4
1032matrix @var{matrix}.
1033@end deffn
1034
19cb171a
DT
1035@node Quaternions
1036@subsection Quaternions
1037
1038In game development, the quaternion is most often used to represent
1039rotations. Why not use a matrix for that, you may ask. Unlike
1040matrices, quaternions can be interpolated (animated) and produce a
1041meaningful result. When interpolating two quaternions, there is a
1042smooth transition from one rotation to another, whereas interpolating
1043two matrices would yield garbage.
1044
1045@deffn {Procedure} quaternion @var{x} @var{y} @var{z} @var{w}
1046Return a new quaternion with values @var{x}, @var{y}, @var{z}, and
1047@var{w}.
1048@end deffn
1049
1050@deffn {Procedure} quaternion? @var{obj}
1051Return @code{#t} if @var{obj} is a quaternion.
1052@end deffn
1053
1054@deffn {Procedure} quaternion-w @var{q}
1055Return the W component of the quaternion @var{q}.
1056@end deffn
1057
1058@deffn {Procedure} quaternion-x @var{q}
1059Return the X component of the quaternion @var{q}.
1060@end deffn
1061
1062@deffn {Procedure} quaternion-y @var{q}
1063Return the Y component of the quaternion @var{q}.
1064@end deffn
1065
1066@deffn {Procedure} quaternion-z @var{q}
1067Return the Z component of the quaternion @var{q}.
1068@end deffn
1069
1070@deffn {Procedure} make-identity-quaternion
1071Return the identity quaternion.
1072@end deffn
1073
dd8cf461
DT
1074@node Easings
1075@subsection Easings
1076
81311e98
DT
1077Easing functions are essential for animation. Each easing function
1078provides a different path to go from an initial value to a final
1079value. These functions make an excellent companion to the
1080@code{tween} procedure (@pxref{Tweening}). Experiment with them to
1081figure out which function makes an animation look the best.
1082
1083Pro tip: @code{smoothstep} provides nice results most of the time and
1084creates smoother animation than using @code{linear}.
1085
4fa48196 1086@deffn {Procedure} linear @var{t}
dd8cf461
DT
1087@end deffn
1088
4fa48196 1089@deffn {Procedure} smoothstep @var{t}
dd8cf461
DT
1090@end deffn
1091
4fa48196 1092@deffn {Procedure} ease-in-quad @var{t}
dd8cf461
DT
1093@end deffn
1094
4fa48196 1095@deffn {Procedure} ease-out-quad @var{t}
dd8cf461
DT
1096@end deffn
1097
4fa48196 1098@deffn {Procedure} ease-in-out-quad @var{t}
dd8cf461
DT
1099@end deffn
1100
4fa48196 1101@deffn {Procedure} ease-in-cubic @var{t}
dd8cf461
DT
1102@end deffn
1103
4fa48196 1104@deffn {Procedure} ease-out-cubic @var{t}
dd8cf461
DT
1105@end deffn
1106
4fa48196 1107@deffn {Procedure} ease-in-out-cubic @var{t}
dd8cf461
DT
1108@end deffn
1109
4fa48196 1110@deffn {Procedure} ease-in-quart @var{t}
dd8cf461
DT
1111@end deffn
1112
4fa48196 1113@deffn {Procedure} ease-out-quart @var{t}
dd8cf461
DT
1114@end deffn
1115
4fa48196 1116@deffn {Procedure} ease-in-out-quart @var{t}
dd8cf461
DT
1117@end deffn
1118
4fa48196 1119@deffn {Procedure} ease-in-quint @var{t}
dd8cf461
DT
1120@end deffn
1121
4fa48196 1122@deffn {Procedure} ease-out-quint @var{t}
dd8cf461
DT
1123@end deffn
1124
4fa48196 1125@deffn {Procedure} ease-in-out-quint @var{t}
dd8cf461
DT
1126@end deffn
1127
4fa48196 1128@deffn {Procedure} ease-in-sine @var{t}
dd8cf461
DT
1129@end deffn
1130
4fa48196 1131@deffn {Procedure} ease-out-sine @var{t}
dd8cf461
DT
1132@end deffn
1133
4fa48196 1134@deffn {Procedure} ease-in-out-sine @var{t}
dd8cf461
DT
1135@end deffn
1136
8f21fe16
DT
1137@node Bezier Curves
1138@subsection Bezier Curves
1139
1140The @code{(chickadee math bezier)} module provides an API for
1141describing cubic Bezier curves in 2D space. These curves are notably
1142used in font description, vector graphics programs, and when it comes
1143to games: path building. With Bezier curves, it's somewhat easy to
1144create a smooth looking path for an enemy to move along, for example.
1145Bezier curves become particularly interesting when they are chained
1146together to form a Bezier ``path'', where the end point of one curve
1147becomes the starting point of the next.
1148
1149Currently, the rendering of Bezier curves is rather crude and provided
1150mostly for visualizing and debugging curves that would be unseen in
1151the final game. See @xref{Lines and Shapes} for more information.
1152
1153@deffn {Procedure} make-bezier-curve @var{p0} @var{p1} @var{p2} @var{p3}
1154Return a new Bezier curve object whose starting point is @var{p0},
1155ending point is @var{p3}, and control points are @var{p1} and
1156@var{p2}. All points are 2D vectors.
1157@end deffn
1158
1159@deffn {Procedure} bezier-curve? @var{obj}
1160Return @code{#t} if @var{obj} is a Bezier curve.
1161@end deffn
1162
1163@deffn {Procedure} bezier-curve-p0 @var{bezier}
1164Return the starting point of @var{bezier}.
1165@end deffn
1166
1167@deffn {Procedure} bezier-curve-p1 @var{bezier}
1168Return the first control point of @var{bezier}.
1169@end deffn
1170
1171@deffn {Procedure} bezier-curve-p2 @var{bezier}
1172Return the second control point of @var{bezier}.
1173@end deffn
1174
1175@deffn {Procedure} bezier-curve-p3 @var{bezier}
1176Return the end point of @var{bezier}.
1177@end deffn
1178
1179@deffn {Procedure} bezier-path . @var{control-points}
1180Return a list of connected bezier curves defined by
1181@var{control-points}. The first curve is defined by the first 4
1182arguments and every additional curve thereafter requires 3 additional
1183arguments.
1184@end deffn
1185
1186@deffn {Procedure} bezier-curve-point-at @var{bezier} @var{t}
1187Return the coordinates for @var{bezier} at @var{t} (a value in the
1188range [0, 1] representing how far from the start of the curve to
1189check) as a 2D vector.
1190@end deffn
1191
1192@deffn {Procedure} bezier-curve-point-at! @var{dest} @var{bezier} @var{t}
1193Modify the 2D vector @var{dest} in-place to contain the coordinates
1194for @var{bezier} at @var{t}.
1195@end deffn
1196
e69ff99c
DT
1197@node Path Finding
1198@subsection Path Finding
1199
1200Most game worlds have maps. Often, these games have a need to move
1201non-player characters around in an unscripted fashion. For example,
1202in a real-time strategy game, the player may command one of their
1203units to attack something in the enemy base. To do so, the unit must
1204calculate the shortest route to get there. It wouldn't be a very fun
1205game if units didn't know how to transport themselves efficiently.
1206This is where path finding algorithms come in handy. The
1207@code{(chickadee math path-finding)} module provides a generic
1208implementation of the popular A* path finding algorithm. Just add a
1209map implementation!
1210
1211The example below defines a very simple town map and finds the
1212quickest way to get from the town common to the school.
1213
1214@example
1215(define world-map
1216 '((town-common . (town-hall library))
1217 (town-hall . (town-common school))
1218 (library . (town-common cafe))
1219 (school . (town-hall cafe))
1220 (cafe . (library school))))
1221(define (neighbors building)
1222 (assq-ref town-map building))
1223(define (cost a b) 1)
1224(define (distance a b) 1)
1225(define pf (make-path-finder))
1226(a* pf 'town-common 'school neighbors cost distance)
1227@end example
1228
1229In this case, the @code{a*} procedure will return the list
1230@code{(town-common town-hall school)}, which is indeed the shortest
1231route. (The other possible route is @code{(town-common library cafe
1232school)}.)
1233
1234The @code{a*} procedure does not know anything about about any kind of
1235map and therefore must be told how to look up neighboring nodes, which
1236is what the @code{neighbors} procedure in the example does. To
1237simulate different types of terrain, a cost procedure is used. In
1238this example, it is just as easy to move between any two nodes because
1239@code{cost} always returns 1. In a real game, perhaps moving from
1240from a field to a rocky hill would cost a lot more than moving from
1241one field to another. Finally, a heuristic is used to calculate an
1242approximate distance between two nodes on the map. In this simple
1243association list based graph it is tough to calculate a distance
1244between nodes, so the @code{distance} procedure isn't helpful and
1245always returns 1. In a real game with a tile-based map, for example,
1246the heuristic could be a quick Manhattan distance calculation based on
1247the coordinates of the two map tiles. Choose an appropriate heuristic
1248for optimal path finding!
1249
1250@deffn {Procedure} make-path-finder
1251Return a new path finder object.
1252@end deffn
1253
1254@deffn {Procedure} path-finder? @var{obj}
1255Return @code{#t} if @var{obj} is a path finder.
1256@end deffn
1257
1258@deffn {Procedure} a* @var{path-finder} @var{start} @var{goal} @
1259 @var{neighbors} @var{cost} @var{distance}
1260
1261Return a list of nodes forming a path from @var{start} to @var{goal}
1262using @var{path-finder} to hold state. @var{neighbors} is a procedure
1263that accepts a node and returns a list of nodes that neighbor it.
1264@var{cost} is a procedure that accepts two neighboring nodes and
1265returns the cost of moving from the first to the second as a real
1266number. @var{distance} is a procedure that accepts two nodes and
1267returns an approximate distance between them.
1268@end deffn
1269
ee2cc0b4
DT
1270@node Graphics
1271@section Graphics
d9350935
DT
1272
1273Chickadee aims to make hardware-accelerated graphics rendering as
1274simple and efficient as possible by providing high-level APIs that
1275interact with the low-level OpenGL API under the hood. Anyone that
1276has worked with OpenGL directly knows that it has a steep learning
1277curve and a lot of effort is needed to render even a single triangle.
1278The Chickadee rendering engine attempts to make it easy to do common
1279tasks like rendering a sprite while also providing all of the building
1280blocks to implement additional rendering techniques.
1281
1282@menu
e46df218 1283* Textures:: 2D images.
d9350935 1284* Sprites:: Draw 2D images.
9c99fc7d 1285* Tile Maps:: Draw 2D tile maps.
d9350935 1286* Lines and Shapes:: Draw line segments and polygons.
e46df218 1287* Fonts:: Drawing text.
5dbd832c 1288* Particles:: Pretty little flying pieces!
7e0b3439 1289* Blending:: Control how pixels are combined.
d9350935 1290* Framebuffers:: Render to texture.
81311e98
DT
1291* Viewports:: Restrict rendering to a particular area.
1292* Rendering Engine:: Rendering state management.
1293* GPU Buffers:: Send data to the GPU.
1294* Shaders:: Create custom GPU programs.
d9350935
DT
1295@end menu
1296
d9350935
DT
1297@node Textures
1298@subsection Textures
1299
4fa48196 1300@deffn {Procedure} load-image @var{file} [#:min-filter nearest] @
44ba82ba
DT
1301 [#:mag-filter nearest] [#:wrap-s repeat] [#:wrap-t repeat]
1302
1303Load the image data from @var{file} and return a new texture object.
1304
1305@var{min-filter} and @var{mag-filter} describe the method that should
1306be used for minification and magnification when rendering,
1307respectively. Possible values are @code{nearest} and @code{linear}.
1308
1309@var{wrap-s} and @var{wrap-t} describe how to interpret texture
1310coordinates that are greater than @code{1.0}. Possible values are
1311@code{repeat}, @code{clamp}, @code{clamp-to-border}, and
1312@code{clamp-to-edge}.
1313
1314@end deffn
1315
e46df218
DT
1316@node Sprites
1317@subsection Sprites
1318
1319For those who are new to this game, a sprite is a 2D rectangular
1320bitmap that is rendered to the screen. For 2D games, sprites are the
1321most essential graphical abstraction. They are used for drawing maps,
1322players, NPCs, items, particles, text, etc. In Chickadee, bitmaps are
1323stored in textures (@pxref{Textures}) and can be used to draw sprites
1324via the @code{draw-sprite} procedure.
1325
fedd9bca
DT
1326@deffn {Procedure} draw-sprite @var{texture} @var{position} @
1327 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
1328 [#:rect] [#:shader]
1329
1330Draw @var{texture} at @var{position}.
1331
1332Optionally, other transformations may be applied to the sprite.
1333@var{rotation} specifies the angle to rotate the sprite, in radians.
1334@var{scale} specifies the scaling factor as a 2D vector. All
1335transformations are applied relative to @var{origin}, a 2D vector,
1336which defaults to the lower-left corner.
1337
1338Alpha blending is used by default but the blending method can be
1339changed by specifying @var{blend-mode}.
1340
1341The area drawn to is as big as the texture, by default. To draw to an
1342arbitrary section of the screen, specify @var{rect}.
e46df218 1343
fedd9bca
DT
1344Finally, advanced users may specify @var{shader} to change the way the
1345sprite is rendered entirely.
e46df218
DT
1346@end deffn
1347
1348It's not uncommon to need to draw hundreds or thousands of sprites
1349each frame. However, GPUs (graphics processing units) are tricky
1350beasts that prefer to be sent few, large chunks of data to render
1351rather than many, small chunks. Using @code{draw-sprite} on its own
1352will involve at least one GPU call @emph{per sprite}, which will
1353quickly lead to poor performance. To deal with this, a technique
1354known as ``sprite batching'' can be used. Instead of drawing each
1355sprite immediately, the sprite batch will build up a large of buffer
1356of sprites to draw and defer rendering until the last possible moment.
1357Batching isn't a panacea, though. Batching only works if the sprites
1358being drawn share as much in common as possible. Every time you draw
1359a sprite with a different texture or blend mode, the batch will be
1360sent off to the GPU. Therefore, batching is most useful if you
1361minimize such changes. A good strategy for reducing texture changes
1362is to stuff many bitmaps into a single image file and create a
1363``texture atlas'' (@pxref{Textures}) to access the sub-images within.
1364
1365Taking advantage of sprite batching in Chickadee is easy, just wrap
1366the code that is calling @code{draw-sprite} a lot in the
1367@code{with-batched-sprites} form.
1368
4fa48196 1369@deffn {Syntax} with-batched-sprites @var{body} @dots{}
e46df218
DT
1370Use batched rendering for all @code{draw-sprite} calls within
1371@var{body}.
1372@end deffn
1373
1374With a basic sprite abstraction in place, it's possible to build other
1375abstractions on top of it. One such example is the ``nine patch''. A
1376nine patch is a sprite that can be rendered at various sizes without
9834292c 1377becoming distorted. This is achieved by dividing up the sprite into
e46df218
DT
1378nine regions:
1379
1380@itemize
1381@item
1382the center, which can be scaled horizontally and vertically
1383@item
1384the four corners, which can never be scaled
1385@item
1386the left and right sides, which can be scaled vertically
1387@item
1388the top and bottom sides, which can be scaled horizontally
1389@end itemize
1390
1391The one caveat is that the bitmap regions must be designed in such a
1392way so that they are not distorted when stretched along the affected
1393axes. For example, that means that the top and bottom sides could
1394have varying colored pixels vertically, but not horizontally.
1395
1396The most common application of this technique is for graphical user
1397interface widgets like buttons and dialog boxes. By using a nine
1398patch, they can be rendered at any size without unappealing scaling
1399artifacts.
1400
fedd9bca 1401@deffn {Procedure} draw-nine-patch @var{texture} @var{rect} @
6306a7dc
DT
1402 [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] @
1403 [#:left-margin margin] [#:right-margin margin] @
fedd9bca 1404 [#:origin] [#:scale] [#:rotation] [#:blend-mode alpha] @
e46df218
DT
1405 [#:shader]
1406
1407Draw a nine patch sprite. A nine patch sprite renders @var{texture}
1408as a @var{width} x @var{height} rectangle whose stretchable areas are
1409defined by the given margin measurements @var{top-margin},
1410@var{bottom-margin}, @var{left-margin}, and @var{right-margin}. The
1411@var{margin} argument may be used to configure all four margins at
1412once.
1413
1414Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1415the other arguments.
1416@end deffn
1417
9c99fc7d
DT
1418@node Tile Maps
1419@subsection Tile Maps
1420
1421A tile map is a scene created by composing lots of small sprites,
1422called ``tiles'', into a larger image. One program for editing such
1423maps is called @url{http://mapeditor.org,Tiled}. Chickadee has native
1424support for loading and rendering Tiled maps in the @code{(chickadee
1425render tiled)} module.
1426
1427@deffn {Procedure} load-tile-map @var{file-name}
1428Load the Tiled formatted map in @var{file-name} and return a new tile
1429map object.
1430@end deffn
1431
1432@deffn {Procedure} draw-tile-map @var{tile-map} [#:layers] [#:region] @
1433 [#:origin] [#:position] [#:scale] [#:rotation]
1434
1435Draw the layers of @var{tile-map}. By default, all layers are drawn.
1436To draw a subset of the available layers, pass a list of layer ids
1437using the @var{layers} keyword argument.
1438
1439Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1440the other arguments.
1441@end deffn
1442
e46df218
DT
1443@node Lines and Shapes
1444@subsection Lines and Shapes
1445
41e434ce
DT
1446Sprites are fun, but sometimes simple, untextured lines and polygons
1447are desired. That's where the @code{(chickadee render shapes)} module
1448comes in!
1449
4fa48196 1450@deffn {Procedure} draw-line @var{start} @var{end} @
41e434ce
DT
1451 [#:thickness 0.5] [#:feather 1.0] [#:cap round] [#:color] @
1452 [#:shader]
1453
1454Draw a line segment from @var{start} to @var{end}. The line will be
1455@var{thickness} pixels thick with an antialiased border @var{feather}
1456pixels wide. The line will be colored @var{color}. @var{cap}
1457specifies the type of end cap that should be used to terminate the
1458lines, either @code{none}, @code{butt}, @code{square}, @code{round},
1459@code{triangle-in}, or @code{triangle-out}. Advanced users may use
1460the @var{shader} argument to override the built-in line segment
1461shader.
1462@end deffn
1463
8f21fe16
DT
1464@deffn {Procedure} draw-bezier-curve @var{bezier} [#:segments 32] @
1465 [#:control-points?] [#:tangents?] @
1466 [#:control-point-size 8] @
1467 [#:control-point-color yellow] @
1468 [#:tangent-color yellow] @
1469 [#:thickness 0.5] [#:feather 1.0] @
1470 [#:matrix]
1471
1472Draw the curve defined by @var{bezier} using a resolution of N
1473@var{segments}. When @var{control-points?} is @code{#t}, the control
1474points are rendered as squares of size @var{control-point-size} pixels
1475and a color of @var{control-point-color}. When @var{tangents?} is
1476@code{#t}, the tangent lines from terminal point to control point are
1477rendered using the color @var{tangent-color}.
1478
1479All line segments rendered use @code{draw-line}, and thus the
1480arguments @var{thickness} and @var{feather} have the same effect as in
1481that procedure.
1482
1483A custom @var{matrix} may be passed for applications that require more
1484control over the final output.
1485@end deffn
1486
1487@deffn {Procedure} draw-bezier-path @var{path} [#:segments 32] @
1488 [#:control-points?] [#:tangents?] @
1489 [#:control-point-size 8] @
1490 [#:control-point-color yellow] @
1491 [#:tangent-color yellow] @
1492 [#:thickness 0.5] [#:feather 1.0] @
1493 [#:matrix]
1494
1495Render @var{path}, a list of bezier curves. See the documentation for
1496@code{draw-bezier-curve} for an explanation of all the keyword
1497arguments.
1498@end deffn
1499
e46df218
DT
1500@node Fonts
1501@subsection Fonts
1502
1503Unlike the traditional TrueType font format that many are accustomed
1504to, Chickadee loads and renders bitmap fonts in the
1505@url{http://www.angelcode.com/products/bmfont/doc/file_format.html,
1506Angel Code format}. But why use this seemingly obscure format? It's
1507easy to find TTFs but not easy to find FNTs (the canonical file
1508extension used for Angel Code fonts) and bitmap fonts don't scale
1509well. The reason is efficiency.
1510
1511If all of the glyphs of a font are pre-rendered and packed into an
1512image file then it becomes possible to use a texture atlas
1513(@pxref{Textures}) and a sprite batch (@pxref{Sprites}) when
1514rendering, which is a more efficient way to render fonts than using,
1515say, @url{https://www.libsdl.org/projects/SDL_ttf/, SDL_ttf} or other
1516solutions that involve using the FreeType library directly.
1517
1518Now what about scaling? In libraries that use TTF fonts, one must
1519choose the size that the glyphs will be rasterized at up front. To
1520use @code{n} sizes of the same font, one must load @code{n} variants
1521of that font. If the size of the text is dynamic, some kind of
1522texture scaling algorithm must be used and the text will inevitably
1523look blurry. At first glance, using bitmap fonts seem to have an even
1524worse issue. Instead of just loading the same font @code{n} times at
1525different sizes, one would need to generate @code{n} image files for
1526each font size needed. This is where the ``signed distance field''
1527rendering technique comes in. Introduced by
1528@url{http://www.valvesoftware.com/.../2007/SIGGRAPH2007_AlphaTestedMagnification.pdf,
1529Valve} in 2007, signed distance field fonts can be efficiently stored
1530in a bitmap and be rendered at arbitrary scale factors with good
fedd9bca 1531results.
e46df218
DT
1532
1533While Chickadee does not yet offer a tool for converting TTF fonts
1534into FNT fonts, tools such as
1535@url{https://github.com/libgdx/libgdx/wiki/Hiero, Hiero} may be used
1536in the meantime.
1537
1538The following procedures can be found in the @code{(chickadee render
1539font)} module.
1540
4fa48196 1541@deffn {Procedure} load-font @var{file}
e46df218
DT
1542Load the Angel Code formatted XML document in @var{file} and return a
1543new font object.
1544@end deffn
1545
4fa48196 1546@deffn {Procedure} font? @var{obj}
e46df218
DT
1547Return @code{#t} if @var{obj} is a font object.
1548@end deffn
1549
4fa48196 1550@deffn {Procedure} font-face @var{font}
e46df218
DT
1551Return the name of @var{font}.
1552@end deffn
1553
4fa48196 1554@deffn {Procedure} font-line-height @var{font}
e46df218
DT
1555Return the line height of @var{font}.
1556@end deffn
1557
4fa48196 1558@deffn {Procedure} font-line-height @var{font}
e46df218
DT
1559Return the line height of @var{font}.
1560@end deffn
1561
4fa48196 1562@deffn {Procedure} font-bold? @var{font}
e46df218
DT
1563Return @code{#t} if @var{font} is a bold font.
1564@end deffn
1565
4fa48196 1566@deffn {Procedure} font-italic? @var{font}
e46df218
DT
1567Return @code{#t} if @var{font} is an italicized font.
1568@end deffn
1569
4fa48196 1570@deffn {Procedure} draw-text @var{font} @var{text} @var{position}
fedd9bca 1571 [#:origin] [#:scale] [#:rotation] [#:blend-mode]
552f0615 1572 [#:start 0] [#:end @code{(string-length text)}]
e46df218
DT
1573
1574Draw the string @var{text} with the first character starting at
1575@var{position} using @var{font}.
1576
1577@example
1578(draw-text font "Hello, world!" (vec2 128.0 128.0))
1579@end example
1580
552f0615
DT
1581To render a substring of @var{text}, use the @var{start} and @var{end}
1582arguments.
1583
e46df218
DT
1584Refer to @code{draw-sprite} (@pxref{Sprites}) for information about
1585the other arguments.
1586@end deffn
1587
5dbd832c
DT
1588@node Particles
1589@subsection Particles
1590
1591Effects like smoke, fire, sparks, etc. are often achieved by animating
1592lots of little, short-lived sprites known as ``particles''. In fact,
1593all of these effects, and more, can be accomplished by turning a few
1594configuration knobs in a ``particle system''. A particle system takes
1595care of managing the many miniscule moving morsels so the developer
1596can quickly produce an effect and move on with their life. The
1597@code{(chickadee render particles)} module provides an API for
1598manipulating particle systems.
1599
1600Below is an example of a very simple particle system that utilizes
1601nearly all of the default configuration settings:
1602
1603@example
1604(use-modules (chickadee render particles))
1605(define texture (load-image "particle.png"))
1606(define particles (make-particles 2000 #:texture texture))
1607@end example
1608
1609In order to put particles into a particle system, a particle
1610``emitter'' is needed. Emitters know where to spawn new particles,
1611how many of them to spawn, and for how long they should do it.
1612
1613Below is an example of an emitter that spawns 16 particles per frame
1614at the coordinates @code{(320, 240)}:
1615
1616@example
1617(use-modules (chickadee math vector))
1618(define emitter (make-particle-emitter (vec2 320.0 240.0) 16))
1619(add-particle-emitter particles emitter)
1620@end example
1621
1622To see all of the tweakable knobs and switches, read on!
1623
1624@deffn {Procedure} make-particles @var{capacity} [#:blend-mode @code{alpha}] @
1625 [#:color white] [#:end-color transparent] [#:texture] @
1626 [#:animation-rows 1] [#:animation-columns 1] [#:width] [#:height] @
1627 [#:speed-range (vec2 0.1 1.0)] [#:acceleration-range (vec2 0.0 0.1)] @
1628 [#:direction-range (vec2 0 (* 2 pi))] [#:lifetime 30] [#:sort]
1629
1630Return a new particle system that may contain up to @var{capacity}
1631particles. Achieving the desired particle effect involves tweaking
1632the following keyword arguments as needed:
1633
1634- @var{blend-mode}: Pixel blending mode. @code{alpha} by default.
7e0b3439 1635(@pxref{Blending} for more about blend modes).
5dbd832c
DT
1636
1637- @var{start-color}: The tint color of the particle at the beginning of its
1638life. White by default.
1639
1640- @var{end-color}: The tint color of the particle at the end of of its
1641life. Completely transparent by default for a fade-out effect. The
1642color in the middle of a particle's life will be an interpolation of
1643@var{start-color} and @var{end-color}.
1644
1645- @var{texture}: The texture applied to the particles. The texture
1646may be subdivided into many animation frames.
1647
1648- @var{animation-rows}: How many animation frame rows there are in the
1649texture. Default is 1.
1650
1651- @var{animation-columns}: How many animation frame columns there are
1652in the texture. Default is 1.
1653
1654- @var{width}: The width of each particle. By default, the width of
1655an animation frame (in pixels) is used.
1656
1657- @var{height}: The height of each particle. By default, the height
1658of an animation frame (in pixels) is used.
1659
1660- @var{speed-range}: A 2D vector containing the min and max particle
1661speed. Each particle will have a speed chosen at random from this
1662range. By default, speed ranges from 0.1 to 1.0.
1663
1664- @var{acceleration-range}: A 2D vector containing the min and max
1665particle acceleration. Each particle will have an acceleration chosen
1666at random from this range. By default, acceleration ranges from 0.0
1667to 0.1.
1668
1669- @var{direction-range}: A 2D vector containing the min and max
1670particle direction as an angle in radians. Each particle will have a
1671direction chosen at random from this range. By default, the range
1672covers all possible angles.
1673
1674- @var{lifetime}: How long each particle lives, measured in
1675updates. 30 by default.
1676
1677- @var{sort}: @code{youngest} if youngest particle should be drawn
1678last or @code{oldest} for the reverse. By default, no sorting is
1679applied at all.
1680@end deffn
1681
1682@deffn {Procedure} particles? @var{obj}
1683Return @code{#t} if @var{obj} is a particle system.
1684@end deffn
1685
1686@deffn {Procedure} update-particles @var{particles}
1687Advance the simulation of @var{particles}.
1688@end deffn
1689
1690@deffn {Procedure} draw-particles @var{particles}
1691Render @var{particles}.
1692@end deffn
1693
1694@deffn {Procedure} draw-particles* @var{particles} @var{matrix}
1695Render @var{particles} with @var{matrix} applied.
1696@end deffn
1697
1698@deffn {Procedure} make-particle-emitter @var{spawn-area} @
1699 @var{rate} [@var{duration}]
1700
1701Return a new particle emitter that spawns @var{rate} particles per
1702frame within @var{spawn-area} (a rectangle or 2D vector) for
1703@var{duration} frames. If @var{duration} is not specified, the
1704emitter will spawn particles indefinitely.
1705@end deffn
1706
1707@deffn {Procedure} particle-emitter? @var{obj}
1708Return @code{#t} if @var{obj} is a particle emitter.
1709@end deffn
1710
1711@deffn {Procedure} particle-emitter-spawn-area @var{emitter}
1712Return the spawn area for @var{emitter}.
1713@end deffn
1714
1715@deffn {Procedure} particle-emitter-rate @var{emitter}
1716Return the number of particles that @var{emitter} will spawn per
1717frame.
1718@end deffn
1719
1720@deffn {Procedure} particle-emitter-life @var{emitter}
1721Return the number of frames remaining in @var{emitter}'s lifespan.
1722@end deffn
1723
1724@deffn {Procedure} particle-emitter-done? @var{emitter}
1725Return @code{#t} if @var{emitter} has finished spawning particlces.
1726@end deffn
1727
1728@deffn {Procedure} add-particle-emitter @var{particles} @var{emitter}
1729Add @var{emitter} to @var{particles}.
1730@end deffn
1731
1732@deffn {Procedure} remove-particle-emitter @var{particles} @var{emitter}
1733Remove @var{emitter} to @var{particles}
1734@end deffn
1735
7e0b3439
DT
1736@node Blending
1737@subsection Blending
d9350935 1738
81311e98
DT
1739Rendering a scene often involves drawing layers of objects that
1740overlap each other. Blending determines how two overlapping pixels
1741are combined in the final image that is rendered to the screen.
1742Chickadee provides the following blend modes:
d9350935 1743
81311e98
DT
1744@itemize
1745
1746@item @code{replace}
1747Use the latest color, ignoring all others.
1748
1749@item @code{alpha}
1750Blend pixels according to the values of their alpha channels. This is
1751the most commonly used blend mode and thus is Chickadee's default
1752mode.
1753
1754@item @code{add}
1755Add all pixel color values together. The more colors blended
1756together, the more white the final color becomes.
1757
1758@item @code{subtract}
1759Subtract all pixel color values. The more colors blended together,
1760the more black the final color becomes.
1761
1762@item @code{multiply}
d9350935 1763
81311e98
DT
1764@item @code{darken}
1765
1766@item @code{lighten}
1767
1768@item @code{screen}
1769
1770@end itemize
d9350935
DT
1771
1772@node Framebuffers
1773@subsection Framebuffers
1774
a7bc573d
DT
1775A framebuffer is a chunk of memory that the GPU can render things
1776onto. By default, the framebuffer that is used for rendering is the
1777one belonging to the game window, but custom framebuffers can be used
1778as well. A common use-case for custom framebuffers is applying
1779post-processing effects: The entire scene is rendered to a
1780framebuffer, and then the contents of that framebuffer are applied to
1781a post-processing shader and rendered to the game window. The
1782post-processing shader could do any number of things: scaling,
1783antialiasing, motion blur, etc.
1784
1785@deffn {Procedure} make-framebuffer @var{width} @var{height} [#:min-filter 'linear] [#:mag-filter 'linear] [#:wrap-s 'repeat] [#:wrap-t 'repeat]
1786
1787Create a new framebuffer that is @var{width} pixels wide and @var{height} pixels high.
1788
1789@var{min-filter} and @var{mag-filter} determine the scaling algorithm
1790applied to the framebuffer when rendering. By default, linear scaling
1791is used in both cases. To perform no smoothing at all, use
1792@code{nearest} for simple nearest neighbor scaling. This is typically
1793the best choice for pixel art games.
1794@end deffn
1795
1796@deffn {Procedure} framebuffer? @var{obj}
1797Return @code{#t} if @var{obj} is a framebuffer.
1798@end deffn
1799
1800@deffn {Procedure} framebuffer-texture @var{fb}
1801Return the texture backing the framebuffer @var{fb}.
1802@end deffn
1803
1804@deffn {Procedure} framebuffer-viewport @var{fb}
1805Return the default viewport (@pxref{Viewports}) used by the
1806framebuffer @var{fb}.
1807@end deffn
1808
1809@deffn {Procedure} null-framebuffer
1810The default framebuffer.
1811@end deffn
1812
d9350935
DT
1813@node Viewports
1814@subsection Viewports
1815
81311e98
DT
1816A viewport represents a subset of the screen (or framebuffer). When
1817rendering a frame, the resulting image will only appear within that
1818viewport. These aren't often needed, and Chickadee's default viewport
1819occupies the entire screen, but there are certain situations where
1820they are useful. For example, a split-screen multiplayer game may
1821render to two different viewports, each occupying a different half of
1822the screen. For information about how to set the current viewport,
1823see @code{with-viewport} in @ref{Rendering Engine}.
1824
1825The @code{(chickadee render viewport)} module provides the following
1826API:
1827
1828@deffn {Procedure} make-viewport @var{x} @var{y} @var{width} @var{height} @
1829 [#:clear-color] [#:clear-flags]
1830
1831Create a viewport that covers an area of the window starting from
1832coordinates (@var{x}, @var{y}) and spanning @var{width} @code{x}
1833@var{height} pixels. Fill the viewport with @var{clear-color} when
1834clearing the screen. Clear the buffers denoted by the list of symbols
1835in @var{clear-flags}.
1836
1837Possible values for @var{clear-flags} are @var{color-buffer},
1838@var{depth-buffer}, @var{accum-buffer}, and @var{stencil-buffer}.
1839@end deffn
1840
1841@deffn {Procedure} viewport? @var{obj}
1842Return @code{#t} if @var{obj} is a viewport.
1843@end deffn
1844
1845@deffn {Procedure} viewport-x @var{viewport}
1846Return the left edge of @var{viewport}.
1847@end deffn
1848
1849@deffn {Procedure} viewport-y @var{viewport}
1850Return the bottom edge of @var{viewport}.
1851@end deffn
1852
1853@deffn {Procedure} viewport-width @var{viewport}
1854Return the width of @var{viewport}.
1855@end deffn
1856
1857@deffn {Procedure} viewport-height @var{viewport}
1858Return the height of @var{viewport}.
1859@end deffn
1860
1861@deffn {Procedure} viewport-clear-color @var{viewport}
1862Return the clear color for @var{viewport}.
1863@end deffn
1864
1865@deffn {Procedure} viewport-clear-flags @var{viewport}
1866Return the list of clear flags for @var{viewport}.
1867@end deffn
1868
1869@node Rendering Engine
1870@subsection Rendering Engine
1871
1872Chickadee defines rendering using a metaphor familiar to Scheme
1873programmers: procedure application. A shader (@pxref{Shaders}) is
1874like a procedure for the GPU to apply. Shaders are passed arguments:
1875A vertex array containing the geometry to render (@pxref{GPU Buffers})
1876and zero or more keyword arguments that the shader understands.
1877Similar to how Scheme has @code{apply} for calling procedures,
1878Chickadee provides @code{gpu-apply} for calling shaders.
1879
1880Additionally, there is some dynamic state that effects how
1881@code{gpu-apply} will behave. Things like the current viewport,
1882framebuffer, and blend mode are stored as dynamic state because it
1883would be tedious to have to have to specify them each time
1884@code{gpu-apply} is called.
1885
1886The following procedures and syntax can be found in the
1887@code{(chickadee render)} module.
1888
1889@deffn {Syntax} gpu-apply @var{shader} @var{vertex-array} @
1890 [#:uniform-key @var{uniform-value} ...]
1891@deffnx {Syntax} gpu-apply* @var{shader} @var{vertex-array} @
1892 @var{count} [#:uniform-key @var{uniform-value} ...]
1893
1894Render @var{vertex-array} using @var{shader} with the uniform values
1895specified in the following keyword arguments.
1896
1897While @code{gpu-apply} will draw every vertex in @var{vertex-array},
1898@code{gpu-apply*} will only draw @var{count} vertices.
1899@end deffn
1900
1901@deffn {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
1902 @var{n} [#:uniform-key @var{uniform-value} ...]
1903@deffnx {Syntax} gpu-apply/instanced @var{shader} @var{vertex-array} @
1904 @var{count} @var{n} [#:uniform-key @var{uniform-value} ...]
1905
1906Render @var{vertex-array} @var{n} times using @var{shader} with the
1907uniform values specified in the following keyword arguments.
1908
1909Instanced rendering is very beneficial for rendering the same object
1910many times with only small differences for each one. For example, the
1911particle effects described in @ref{Particles} use instanced rendering.
1912
1913While @code{gpu-apply/instanced} will draw every vertex in
1914@var{vertex-array}, @code{gpu-apply*} will only draw @var{count}
1915vertices.
1916@end deffn
1917
1918@deffn {Procedure} current-viewport
1919Return the currently bound viewport (@pxref{Viewports}).
1920@end deffn
1921
1922@deffn {Procedure} current-framebuffer
1923Return the currently bound framebuffer (@pxref{Framebuffers}).
1924@end deffn
1925
1926@deffn {Procedure} current-blend-mode
7e0b3439 1927Return the currently bound blend mode (@pxref{Blending}).
81311e98
DT
1928@end deffn
1929
1930@deffn {Procedure} current-depth-test
7e0b3439 1931Return @code{#t} if depth testing is currently enabled (@pxref{Blending}).
81311e98
DT
1932@end deffn
1933
1934@deffn {Procedure} current-texture
1935Return the currently bound texture (@pxref{Textures}).
1936@end deffn
1937
1938@deffn {Procedure} current-projection
1939Return the currently bound projection matrix (@pxref{Matrices}).
1940@end deffn
1941
1942@deffn {Syntax} with-viewport @var{viewport} @var{body} ...
1943Evaluate @var{body} with the current viewport bound to @var{viewport} (@pxref{Viewports}).
1944@end deffn
1945
1946@deffn {Syntax} with-framebuffer @var{framebuffer} @var{body} ...
1947Evaluate @var{body} with the current framebuffer bound to
1948@var{framebuffer} (@pxref{Framebuffers}).
1949@end deffn
1950
1951@deffn {Syntax} with-blend-mode @var{blend-mode} @var{body} ...
1952Evaluate @var{body} with the current blend mode bound to
7e0b3439 1953@var{blend-mode} (@pxref{Blending}).
81311e98
DT
1954@end deffn
1955
1956@deffn {Syntax} with-depth-test @var{depth-test?} @var{body} ...
1957Evaluate @var{body} with the depth-test disabled if @var{depth-test?}
7e0b3439 1958is @code{#f}, or enabled otherwise (@pxref{Blending}).
81311e98
DT
1959@end deffn
1960
1961@deffn {Syntax} with-texture @var{texture} @var{body} ...
1962Evaluate @var{body} with the current texture bound to @var{texture}
1963(@pxref{Textures}).
1964@end deffn
1965
1966@deffn {Syntax} with-projection @var{projection} @var{body} ...
1967Evaluate @var{body} with the current projection matrix bound to
1968@var{projection} (@pxref{Matrices}).
1969@end deffn
1970
1971@node GPU Buffers
1972@subsection GPU Buffers
1973
1974Alright, let's brush aside all of those pretty high level abstractions
1975and discuss what is going on under the hood. The GPU exists as a
1976discrete piece of hardware separate from the CPU. In order to make it
1977draw things, we must ship lots of data out of our memory space and
1978into the GPU. The @code{(chickadee render buffer}) module provides an
1979API for manipulating GPU buffers.
1980
1981In OpenGL terminology, a chunk of data allocated on the GPU is a
1982``vertex buffer object'' or VBO. For example, here is a bytevector
1983that could be transformed into a GPU buffer that packs together vertex
1984position and texture coordinates:
1985
1986@example
1987(use-modules (chickadee render buffer) (srfi srfi-4))
1988(define data
1989 (f32vector -8.0 -8.0 ; 2D vertex
1990 0.0 0.0 ; 2D texture coordinate
1991 8.0 -8.0 ; 2D vertex
1992 1.0 0.0 ; 2D texture coordinate
1993 8.0 8.0 ; 2D vertex
1994 1.0 1.0 ; 2D texture coordinate
1995 -8.0 8.0 ; 2d vertex
1996 0.0 1.0)) ; 2D texture coordinate
1997@end example
1998
1999This data represents a textured 16x16 square centered on the
2000origin. To send this data to the GPU, the @code{make-buffer} procedure
2001is needed:
2002
2003@example
2004(define buffer (make-buffer data #:stride 16)
2005@end example
2006
2007The @code{#:stride} keyword argument indicates how many bytes make up
2008each element of the buffer. In this case, there are 4 floats per
2009element: 2 for the vertex, and 2 for the texture coordinate. A 32-bit
2010float is 4 bytes in length, so the buffer's stride is 16.
2011
2012Within a VBO, one or more ``attributes'', as OpenGL calls them, may be
2013present. Attributes are subregions within the buffer that have a
2014particular data type. In this case, there are two attributes packed
2015into the buffer. To provided a typed view into a buffer, the
2016@code{make-typed-buffer} is needed:
2017
2018@example
2019(define vertices
2020 (make-typed-buffer #:buffer buffer
2021 #:type 'vec2
2022 #:component-type 'float
2023 #:length 4))
2024(define texcoords
2025 (make-typed-buffer #:buffer buffer
2026 #:type 'vec2
2027 #:component-type 'float
2028 #:length 4
2029 #:offset 8))
2030@end example
2031
2032To render a square, the GPU needs to draw two triangles, which means
2033we need 6 vertices in total. However, the above buffer only contains
2034data for 4 vertices. This is becase there are only 4 unique vertices
2035for a square, but 2 of them must be repeated for each triangle. To
2036work with deduplicated vertex data, an ``index buffer'' must be
2037created.
2038
2039@example
2040(define index-buffer
2041 (make-buffer (u32vector 0 3 2 0 2 1)
2042 #:target 'index)
2043(define indices
2044 (make-typed-buffer #:type 'scalar
2045 #:component-type 'unsigned-int
2046 #:buffer index-buffer))
2047@end example
2048
2049Note the use of the @code{#:target} keyword argument. It is required
2050because the GPU treats index data in a special way and must be told
2051which data is index data.
2052
2053Now that the typed buffers representing each attribute have been
2054created, all that's left is to bind them all together in a ``vertex
2055array object'', or VAO. Vertex arrays associate each typed buffer
2056with an attribute index on the GPU. The indices that are chosen must
2057correspond with the indices that the shader (@pxref{Shaders}) expects
2058for each attribute.
2059
2060@example
2061(define vertex-array
2062 (make-vertex-array #:indices indices
2063 #:attributes `((0 . ,vertices)
2064 (1 . ,texcoords))))
2065@end example
2066
2067With the vertex array created, the GPU is now fully aware of how to
2068interpret the data that it has been given in the original buffer.
2069Actually rendering this square is left as an exercise to the reader.
2070See the @ref{Shaders} section and the @code{gpu-apply} procedure in
2071@ref{Rendering Engine} the remaining pieces of a successful draw call.
2072Additionally, consider reading the source code for sprites, shapes, or
2073particles to see GPU buffers in action.
2074
2075Without further ado, the API reference:
2076
2077@deffn {Procedure} make-buffer @var{data} [#:name "anonymous"] @
2078 [#:length] [#:offset 0] [#:stride 0] [#:target @code{vertex}] @
2079 [#:usage @code{static}]
2080
2081Upload @var{data}, a bytevector, to the GPU. By default, the entire
2082bytevector is uploaded. A subset of the data may be uploaded by
2083specifying the @var{offset}, the index of the first byte to be
2084uploaded, and @var{length}, the number of bytes to upload.
2085
2086If @var{data} is @code{#f}, allocate @var{length} bytes of fresh GPU
2087memory instead.
2088
2089@var{target} and @var{usage} are hints that tell the GPU how the
2090buffer is intended to be used.
2091
2092@var{target} may be:
2093
2094@itemize
2095@item @code{vertex}
2096Vertex attribute data.
2097
2098@item @code{index}
2099Index buffer data.
2100
2101@end itemize
2102
2103@var{usage} may be:
2104
2105@itemize
2106@item @code{static}
2107The buffer data will not be modified after creation.
2108
2109@item @code{stream}
2110The buffer data will be modified frequently.
2111
2112@end itemize
2113
2114@var{name} is simply an arbitrary string for debugging purposes that
2115is never sent to the GPU.
2116@end deffn
2117
2118@deffn {Procedure} buffer? @var{obj}
2119Return @code{#t} if @var{obj} is a GPU buffer.
2120@end deffn
2121
2122@deffn {Procedure} index-buffer? @var{buffer}
2123Return @code{#t} if @var{buffer} is an index buffer.
2124@end deffn
2125
2126@defvar null-buffer
2127Represents the absence of a buffer.
2128@end defvar
2129
2130@deffn {Procedure} buffer-name @var{buffer}
2131Return the name of @var{buffer}.
2132@end deffn
2133
2134@deffn {Procedure} buffer-length @var{buffer}
2135Return the length of @var{buffer}.
2136@end deffn
2137
2138@deffn {Procedure} buffer-stride @var{buffer}
2139Return the amount of space, in bytes, between each element in
2140@var{buffer}.
2141@end deffn
2142
2143@deffn {Procedure} buffer-target @var{buffer}
2144Return the the intended usage of @var{buffer}, either @code{vertex} or
2145@code{index}.
2146@end deffn
2147
2148@deffn {Procedure} buffer-usage @var{buffer}
2149Return the intended usage of @var{buffer}, either @code{static} for
2150buffer data that will not change once sent to the GPU, or
2151@code{stream} for buffer data that will be frequently updated from the
2152client-side.
2153@end deffn
2154
2155@deffn {Procedure} buffer-data @var{buffer}
2156Return a bytevector containing all the data within @var{buffer}. If
2157@var{buffer} has not been mapped (see @code{with-mapped-buffer}) then
2158this procedure will return @code{#f}.
2159@end deffn
2160
2161@deffn {Syntax} with-mapped-buffer @var{buffer} @var{body} @dots{}
2162Evaluate @var{body} in the context of @var{buffer} having its data
2163synced from GPU memory to RAM. In this context, @code{buffer-data}
2164will return a bytevector of all the data stored in @var{buffer}. When
2165program execution exits this form, the data (including any
2166modifications) is synced back to the GPU.
2167
2168This form is useful for streaming buffers that need to update their
2169contents dynamically, such as a sprite batch.
2170@end deffn
2171
2172@deffn {Procedure} make-typed-buffer #:buffer #:type @
2173 #:component-type #:length [#:offset 0] [#:divisor] @
2174 [#:name "anonymous"]
2175
2176Return a new typed buffer view for @var{buffer} starting at byte index
2177@var{offset} of @var{length} elements, where each element is of
2178@var{type} and composed of @var{component-type} values.
2179
2180Valid values for @var{type} are:
2181
2182@itemize
2183@item @code{scalar}
2184single number
2185
2186@item @code{vec2}
21872D vector
2188
2189@item @code{vec3}
21903D vector
2191
2192@item @code{vec4}
21934D vector
2194
2195@item @code{mat2}
21962x2 matrix
2197
2198@item @code{mat3}
21993x3 matrix
2200
2201@item @code{mat4}
22024x4 matrix
2203@end itemize
2204
2205Valid values for @var{component-type} are:
2206
2207@itemize
2208
2209@item @code{byte}
2210@item @code{unsigned-byte}
2211@item @code{short}
2212@item @code{unsigned-short}
2213@item @code{int}
2214@item @code{unsigned-int}
2215@item @code{float}
2216@item @code{double}
2217
2218@end itemize
2219
2220@var{divisor} is only needed for instanced rendering applications (see
2221@code{gpu-apply/instanced} in @ref{Rendering Engine}) and represents
2222how many instances each vertex element applies to. A divisor of 0
2223means that a single element is used for every instance and is used for
2224the data being instanced. A divisor of 1 means that each element is
2225used for 1 instance. A divisor of 2 means that each element is used
2226for 2 instances, and so on.
2227@end deffn
2228
2229@deffn {Procedure} typed-buffer? @var{obj}
2230Return @code{#t} if @var{obj} is a typed buffer.
2231@end deffn
2232
2233@deffn {Procedure} typed-buffer->buffer @var{typed-buffer}
2234Return the buffer that @var{typed-buffer} is using.
2235@end deffn
2236
2237@deffn {Procedure} typed-buffer-name @var{typed-buffer}
2238Return the name of @var{typed-buffer}.
2239@end deffn
2240
2241@deffn {Procedure} typed-buffer-offset @var{typed-buffer}
2242Return the byte offset of @var{typed-buffer}.
2243@end deffn
2244
2245@deffn {Procedure} typed-buffer-type @var{typed-buffer}
2246Return the data type of @var{typed-buffer}.
2247@end deffn
2248
2249@deffn {Procedure} typed-buffer-component-type @var{typed-buffer}
2250Return the component data type of @var{typed-buffer}
2251@end deffn
2252
2253@deffn {Procedure} typed-buffer-divisor @var{typed-buffer}
2254Return the instance divisor for @var{typed-buffer}.
2255@end deffn
2256
2257@deffn {Syntax} with-mapped-typed-buffer @var{typed-buffer} @var{body} @dots{}
2258
2259Evaluate @var{body} in the context of @var{typed-buffer} having its
2260data synced from GPU memory to RAM. See @code{with-mapped-buffer} for
2261more information.
2262@end deffn
2263
2264@deffn {Procedure} make-vertex-array #:indices #:attributes @
2265 [#:mode @code{triangles}]
2266
2267Return a new vertex array using the index data within the typed buffer
2268@var{indices} and the vertex attribute data within @var{attributes}.
2269
2270@var{attributes} is an alist mapping shader attribute indices to typed
2271buffers containing vertex data:
2272
2273@example
2274`((1 . ,typed-buffer-a)
2275 (2 . ,typed-buffer-b)
2276 ...)
2277@end example
2278
2279By default, the vertex array is interpreted as containing a series of
2280triangles. If another primtive type is desired, the @var{mode}
2281keyword argument may be overridden. The following values are
2282supported:
2283
2284@itemize
2285@item @code{points}
2286@item @code{lines}
2287@item @code{line-loop}
2288@item @code{line-strip}
2289@item @code{triangles}
2290@item @code{triangle-strip}
2291@item @code{triangle-fan}
2292@end itemize
2293
2294@end deffn
2295
2296@defvar null-vertex-array
2297Represents the absence of a vertex array.
2298@end defvar
2299
2300@deffn {Procedure} vertex-array? @var{obj}
2301Return @code{#t} if @var{obj} is a vertex array.
2302@end deffn
2303
2304@deffn {Procedure} vertex-array-indices @var{vertex-array}
2305Return the typed buffer containing index data for @var{vertex-array}.
2306@end deffn
2307
2308@deffn {Procedure} vertex-array-attributes @var{vertex-array}
2309Return the attribute index -> typed buffer mapping of vertex attribute
2310data for @var{vertex-array}.
2311@end deffn
2312
2313@deffn {Procedure} vertex-array-mode @var{vertex-array}
2314Return the primitive rendering mode for @var{vertex-array}.
2315@end deffn
2316
2317@node Shaders
2318@subsection Shaders
2319
2320Shaders are programs that the GPU can evaluate that allow the
2321programmer to completely customized the final output of a GPU draw
2322call. The @code{(chickadee render shader)} module provides an API for
2323building custom shaders.
2324
2325Shaders are written in the OpenGL Shading Language, or GLSL for short.
2326Chickadee aspires to provide a domain specific language for writing
2327shaders in Scheme, but we are not there yet.
2328
2329Shader programs consist of two components: A vertex shader and a
2330fragment shader. A vertex shader receives vertex data (position
2331coordinates, texture coordinates, normals, etc.) and transforms them
2332as desired, whereas a fragment shader controls the color of each
2333pixel.
2334
2335Sample vertex shader:
2336
2337@example
2338@verbatim
2339#version 130
2340
2341in vec2 position;
2342in vec2 tex;
2343out vec2 fragTex;
2344uniform mat4 mvp;
2345
2346void main(void) {
2347 fragTex = tex;
2348 gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
2349}
2350@end verbatim
2351@end example
2352
2353Sample fragment shader:
2354
2355@example
2356@verbatim
2357#version 130
2358
2359in vec2 fragTex;
2360uniform sampler2D colorTexture;
2361
2362void main (void) {
2363 gl_FragColor = texture2D(colorTexture, fragTex);
2364}
2365@end verbatim
2366@end example
2367
2368This manual will not cover GLSL features and syntax as there is lots
2369of information already available about this topic.
2370
2371One way to think about rendering with shaders, and the metaphor
2372Chickadee uses, is to think about it as a function call: The shader is
2373a function, and it is applied to some ``attributes'' (positional
2374arguments), and some ``uniforms'' (keyword arguments).
2375
2376@example
2377(define my-shader (load-shader "vert.glsl" "frag.glsl"))
2378(define vertices (make-vertex-array ...))
2379(gpu-apply my-shader vertices #:color red)
2380@end example
2381
2382@xref{Rendering Engine} for more details about the @code{gpu-apply}
2383procedure.
2384
2385Shaders are incredibly powerful tools, and there's more information
2386about them than we could ever fit into this manual, so we highly
2387recommend searching the web for more information and examples. What
2388we can say, though, is how to use our API:
2389
2390@deffn {Procedure} strings->shader @var{vertex-source} @var{fragment-source}
2391Compile @var{vertex-source}, the GLSL code for the vertex shader, and
2392@var{fragment-source}, the GLSL code for the fragment shader, into a
2393GPU shader program.
2394@end deffn
2395
2396@deffn {Procedure} load-shader @var{vertex-source-file} @
2397 @var{fragment-source-file}
2398
2399Compile the GLSL source code within @var{vertex-source-file} and
2400@var{fragment-source-file} into a GPU shader program.
2401@end deffn
2402
2403@deffn {Procedure} make-shader @var{vertex-port} @var{fragment-port}
2404Read GLSL source from @var{vertex-port} and @var{fragment-port} and
2405compile them into a GPU shader program.
2406@end deffn
2407
2408@deffn {Procedure} shader? @var{obj}
2409Return @code{#t} if @var{obj} is a shader.
2410@end deffn
2411
2412@defvar null-shader
2413Represents the absence shader program.
2414@end defvar
2415
2416@deffn {Procedure} shader-uniform @var{shader} @var{name}
2417Return the metadata for the uniform @var{name} in @var{shader}.
2418@end deffn
2419
2420@deffn {Procedure} shader-uniforms @var{shader}
2421Return a hash table of uniforms for @var{shader}.
2422@end deffn
2423
2424@deffn {Procedure} shader-attributes @var{shader}
2425Return a hash table of attributes for @var{shader}.
2426@end deffn
2427
2428@deffn {Procedure} uniform? @var{obj}
2429Return @code{#t} if @var{obj} is a uniform.
2430@end deffn
2431
2432@deffn {Procedure} uniform-name @var{uniform}
2433Return the variable name of @var{uniform}.
2434@end deffn
2435
2436@deffn {Procedure} uniform-type @var{uniform}
2437Return the data type of @var{uniform}.
2438@end deffn
2439
2440@deffn {Procedure} uniform-value @var{uniform}
2441Return the current value of @var{uniform}.
2442@end deffn
2443
2444@deffn {Procedure} uniform-default-value @var{uniform}
2445Return the default value of @var{uniform}.
2446@end deffn
2447
2448@deffn {Procedure} attribute? @var{obj}
2449Return @code{#t} if @var{obj} is an attribute.
2450@end deffn
2451
2452@deffn {Procedure} attribute-name @var{attribute}
2453Return the variable name of @var{attribute}.
2454@end deffn
2455
2456@deffn {Procedure} attribute-location @var{attribute}
2457Return the binding location of @var{attribute}.
2458@end deffn
2459
2460@deffn {Procedure} attribute-type @var{attribute}
2461Return the data type of @var{attribute}.
2462@end deffn
2463
6a182194
DT
2464@node Scripting
2465@section Scripting
2466
2467Game logic is a web of asynchronous events that are carefully
2468coordinated to bring the game world to life. In order to make an
2469enemy follow and attack the player, or move an NPC back and forth in
2470front of the item shop, or do both at the same time, a scripting
2471system is a necessity. Chickadee comes with an asynchronous
2472programming system in the @code{(chickadee scripting)} module.
88534f74 2473Lightweight, cooperative threads known as ``scripts'' allow the
6a182194
DT
2474programmer to write asynchronous code as if it were synchronous, and
2475allow many such ``threads'' to run concurrently.
2476
88534f74 2477But before we dig deeper into scripts, let's discuss the simple act
6a182194
DT
2478of scheduling tasks.
2479
2480@menu
2481* Agendas:: Scheduling tasks.
88534f74 2482* Scripts:: Cooperative multitasking.
dd8cf461 2483* Tweening:: Animations.
6a182194
DT
2484* Channels:: Publish data to listeners.
2485@end menu
2486
2487@node Agendas
2488@subsection Agendas
2489
2490To schedule a task to be performed later, an ``agenda'' is used.
2491There is a default, global agenda that is ready to be used, or
2492additional agendas may be created for different purposes. The
2493following example prints the text ``hello'' when the agenda has
2494advanced to time unit 10.
2495
2496@example
2497(at 10 (display "hello\n"))
2498@end example
2499
2500Most of the time it is more convenient to schedule tasks relative to
2501the current time. This is where @code{after} comes in handy:
2502
2503@example
2504(after 10 (display "hello\n"))
2505@end example
2506
2507Time units in the agenda are in no way connected to real time. It's
2508up to the programmer to decide what agenda time means. A simple and
2509effective approach is to map each call of the update hook
2510(@pxref{Kernel}) to 1 unit of agenda time, like so:
2511
2512@example
2513(add-hook! update-hook (lambda (dt) (update-agenda 1)))
2514@end example
2515
2516It is important to call @code{update-agenda} periodically, otherwise
2517no tasks will ever be run!
2518
2519In addition to using the global agenda, it is useful to have multiple
2520agendas for different purposes. For example, the game world can use a
2521different agenda than the user interface, so that pausing the game is
2522a simple matter of not updating the world's agenda while continuing to
2523update the user interface's agenda. The current agenda is dynamically
2524scoped and can be changed using the @code{with-agenda} special form:
2525
2526@example
2527(define game-world-agenda (make-agenda))
2528
2529(with-agenda game-world-agenda
2530 (at 60 (spawn-goblin))
2531 (at 120 (spawn-goblin))
2532 (at 240 (spawn-goblin-king)))
2533@end example
2534
4fa48196 2535@deffn {Procedure} make-agenda
6a182194
DT
2536Return a new task scheduler.
2537@end deffn
2538
4fa48196 2539@deffn {Procedure} agenda? @var{obj}
6a182194
DT
2540Return @code{#t} if @var{obj} is an agenda.
2541@end deffn
2542
4fa48196
DT
2543@deffn {Procedure} current-agenda
2544@deffnx {Procedure} current-agenda @var{agenda}
6a182194
DT
2545When called with no arguments, return the current agenda. When called
2546with one argument, set the current agenda to @var{agenda}.
2547@end deffn
2548
4fa48196 2549@deffn {Syntax} with-agenda @var{agenda} @var{body} @dots{}
6a182194
DT
2550Evaluate @var{body} with the current agenda set to @var{agenda}.
2551@end deffn
2552
4fa48196 2553@deffn {Procedure} agenda-time
6a182194
DT
2554Return the current agenda time.
2555@end deffn
2556
4fa48196 2557@deffn {Procedure} update-agenda @var{dt}
6a182194
DT
2558Advance the current agenda by @var{dt}.
2559@end deffn
2560
4fa48196 2561@deffn {Procedure} schedule-at @var{time} @var{thunk}
6a182194
DT
2562Schedule @var{thunk}, a procedure of zero arguments, to be run at
2563@var{time}.
2564@end deffn
2565
4fa48196 2566@deffn {Procedure} schedule-after @var{delay} @var{thunk}
6a182194
DT
2567Schedule @var{thunk}, a procedure of zero arguments, to be run after
2568@var{delay}.
2569@end deffn
2570
4fa48196 2571@deffn {Procedure} schedule-every @var{interval} @var{thunk} [@var{n}]
5e8aab99
DT
2572Schedule @var{thunk}, a procedure of zero arguments, to be run every
2573@var{interval} amount of time. Repeat this @var{n} times, or
2574indefinitely if not specified.
2575@end deffn
2576
4fa48196 2577@deffn {Syntax} at @var{time} @var{body} @dots{}
6a182194
DT
2578Schedule @var{body} to be evaluated at @var{time}.
2579@end deffn
2580
4fa48196 2581@deffn {Syntax} after @var{delay} @var{body} @dots{}
6a182194
DT
2582Schedule @var{body} to be evaluated after @var{delay}.
2583@end deffn
2584
4fa48196
DT
2585@deffn {Syntax} every @var{interval} @var{body} @dots{}
2586@deffnx {Syntax} every (@var{interval} @var{n}) @var{body} @dots{}
5e8aab99
DT
2587Schedule @var{body} to be evaluated every @var{interval} amount of
2588time. Repeat this @var{n} times, or indefinitely if not specified.
2589@end deffn
2590
88534f74
DT
2591@node Scripts
2592@subsection Scripts
6a182194
DT
2593
2594Now that we can schedule tasks, let's take things to the next level.
2595It sure would be great if we could make procedures that described a
2596series of actions that happened over time, especially if we could do
2597so without contorting our code into a nest of callback procedures.
88534f74
DT
2598This is where scripts come in. With scripts we can write code in a
2599linear way, in a manner that appears to be synchronous, but with the
2600ability to suspend periodically in order to let other scripts have a
2601turn and prevent blocking the game loop. Building on top of the
2602scheduling that agendas provide, here is a script that models a child
2603trying to get their mother's attention:
6a182194
DT
2604
2605@example
88534f74 2606(script
6a182194
DT
2607 (while #t
2608 (display "mom!")
2609 (newline)
6eccb107 2610 (sleep 60))) ; where 60 = 1 second of real time
6a182194
DT
2611@end example
2612
6eccb107 2613This code runs in an endless loop, but the @code{sleep} procedure
88534f74 2614suspends the script and schedules it to be run later by the agenda.
6a182194
DT
2615So, after each iteration of the loop, control is returned back to the
2616game loop and the program is not stuck spinning in a loop that will
2617never exit. Pretty neat, eh?
2618
88534f74
DT
2619Scripts can suspend to any capable handler, not just the agenda.
2620The @code{yield} procedure will suspend the current script and pass
6a182194
DT
2621its ``continuation'' to a handler procedure. This handler procedure
2622could do anything. Perhaps the handler stashes the continuation
2623somewhere where it will be resumed when the user presses a specific
2624key on the keyboard, or maybe it will be resumed when the player picks
2625up an item off of the dungeon floor; the sky is the limit.
2626
88534f74
DT
2627Sometimes it is necessary to abruptly terminate a script after it has
2628been started. For example, when an enemy is defeated their AI routine
2629needs to be shut down. When a script is spawned, a handle to that
2630script is returned that can be used to cancel it when desired.
6a182194
DT
2631
2632@example
6eccb107 2633(define script (script (while #t (display "hey\n") (sleep 60))))
6a182194 2634;; sometime later
88534f74 2635(cancel-script script)
6a182194
DT
2636@end example
2637
88534f74
DT
2638@deffn {Procedure} spawn-script @var{thunk}
2639Apply @var{thunk} as a script and return a handle to it.
6a182194
DT
2640@end deffn
2641
88534f74
DT
2642@deffn {Syntax} script @var{body} @dots{}
2643Evaluate @var{body} as a script and return a handle to it.
6a182194
DT
2644@end deffn
2645
88534f74
DT
2646@deffn {Procedure} script? @var{obj}
2647Return @code{#t} if @var{obj} is a script handle.
6a182194
DT
2648@end deffn
2649
88534f74 2650@deffn {Procedure} script-cancelled? @var{obj}
6a182194
DT
2651Return @code{#t} if @var{obj} has been cancelled.
2652@end deffn
2653
88534f74 2654@deffn {Procedure} script-running? @var{obj}
6a182194
DT
2655Return @code{#t} if @var{obj} has not yet terminated or been
2656cancelled.
2657@end deffn
2658
88534f74 2659@deffn {Procedure} script-complete? @var{obj}
6a182194
DT
2660Return @code{#t} if @var{obj} has terminated.
2661@end deffn
2662
88534f74
DT
2663@deffn {Procedure} cancel-script @var{co}
2664Prevent further execution of the script @var{co}.
6a182194
DT
2665@end deffn
2666
4fa48196 2667@deffn {Procedure} yield @var{handler}
88534f74 2668Suspend the current script and pass its continuation to the
6a182194
DT
2669procedure @var{handler}.
2670@end deffn
2671
6eccb107 2672@deffn {Procedure} sleep @var{duration}
88534f74 2673Wait @var{duration} before resuming the current script.
6a182194
DT
2674@end deffn
2675
4fa48196 2676@deffn {Syntax} forever @var{body} @dots{}
6a182194
DT
2677Evaluate @var{body} in an endless loop.
2678@end deffn
2679
dd8cf461
DT
2680@node Tweening
2681@subsection Tweening
2682
2683Tweening is the process of transitioning something from an initial
2684state to a final state over a pre-determined period of time. In other
2685words, tweening is a way to create animation. The @code{tween}
88534f74 2686procedure can be used within any script like so:
dd8cf461
DT
2687
2688@example
2689(define x 0)
88534f74 2690(script
dd8cf461
DT
2691 ;; 0 to 100 in 60 ticks of the agenda.
2692 (tween 60 0 100 (lambda (y) (set! x y))))
2693@end example
2694
4fa48196 2695@deffn {Procedure} tween @var{duration} @var{start} @var{end} @var{proc} [#:step 1 #:ease @code{smoothstep} #:interpolate @code{lerp}]
dd8cf461
DT
2696Transition a value from @var{start} to @var{end} over @var{duration},
2697sending each succesive value to @var{proc}. @var{step} controls the
2698amount of time between each update of the animation.
2699
2700To control how the animation goes from the initial to final state, an
2701``easing'' procedure may be specified. By default, the
2702@code{smoothstep} easing is used, which is a more pleasing default
88534f74
DT
2703than a simplistic linear function. @xref{Easings} for a complete list
2704of available easing procedures.
dd8cf461
DT
2705
2706The @var{interpolate} procedure computes the values in between
2707@var{start} and @var{end}. By default, linear interpolation (``lerp''
2708for short) is used.
2709@end deffn
2710
6a182194
DT
2711@node Channels
2712@subsection Channels
2713
88534f74
DT
2714Channels are a tool for communicating amongst different scripts. One
2715script can write a value to the channel and another can read from it.
2716Reading or writing to a channel suspends that script until there is
2717someone on the other end of the line to complete the transaction.
6a182194
DT
2718
2719Here's a simplistic example:
2720
2721@example
2722(define c (make-channel))
2723
88534f74 2724(script
6a182194
DT
2725 (forever
2726 (let ((item (channel-get c)))
2727 (pk 'got item))))
2728
88534f74 2729(script
6a182194
DT
2730 (channel-put c 'sword)
2731 (channel-put c 'shield)
2732 (channel-put c 'potion))
2733@end example
2734
4fa48196 2735@deffn {Procedure} make-channel
6a182194
DT
2736Return a new channel
2737@end deffn
2738
4fa48196 2739@deffn {Procedure} channel? @var{obj}
6a182194
DT
2740Return @code{#t} if @var{obj} is a channel.
2741@end deffn
2742
4fa48196 2743@deffn {Procedure} channel-get @var{channel}
88534f74 2744Retrieve a value from @var{channel}. The current script suspends
6a182194
DT
2745until a value is available.
2746@end deffn
2747
4fa48196 2748@deffn {Procedure} channel-put @var{channel} @var{data}
88534f74
DT
2749Send @var{data} to @var{channel}. The current script suspends until
2750another script is available to retrieve the value.
6a182194 2751@end deffn
fb8f3bcd
DT
2752
2753A low-level API also exists for using channels outside of a script via
2754callback procedures:
2755
2756@deffn {Procedure} channel-get! @var{channel} @var{proc}
2757Asynchronously retrieve a value from @var{channel} and call @var{proc}
2758with that value.
2759@end deffn
2760
2761@deffn {Procedure} channel-put! @var{channel} @var{data} [@var{thunk}]
2762Asynchronously send @var{data} to @var{channel} and call @var{thunk}
2763after it has been received.
2764@end deffn