From e46df21886b186cfcf28008eac4b9cb6577b4689 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Tue, 24 Jan 2017 20:22:09 -0500 Subject: doc: Document sprites and fonts. --- doc/api.texi | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 7 deletions(-) (limited to 'doc') diff --git a/doc/api.texi b/doc/api.texi index 1524acc..554b531 100644 --- a/doc/api.texi +++ b/doc/api.texi @@ -414,9 +414,10 @@ blocks to implement additional rendering techniques. @menu * Rendering Engine:: Rendering state management. +* Textures:: 2D images. * Sprites:: Draw 2D images. * Lines and Shapes:: Draw line segments and polygons. -* Textures:: 2D images. +* Fonts:: Drawing text. * Blending and Depth Testing:: Control how pixels are combined. * Vertex Arrays:: Create 2D/3D models. * Shaders:: Create custom GPU programs. @@ -514,12 +515,6 @@ Evaluate @var{body} with the current projection matrix bound to @var{projection}. @end deffn -@node Sprites -@subsection Sprites - -@node Lines and Shapes -@subsection Lines and Shapes - @node Textures @subsection Textures @@ -539,6 +534,180 @@ coordinates that are greater than @code{1.0}. Possible values are @end deffn +@node Sprites +@subsection Sprites + +For those who are new to this game, a sprite is a 2D rectangular +bitmap that is rendered to the screen. For 2D games, sprites are the +most essential graphical abstraction. They are used for drawing maps, +players, NPCs, items, particles, text, etc. In Chickadee, bitmaps are +stored in textures (@pxref{Textures}) and can be used to draw sprites +via the @code{draw-sprite} procedure. + +@deffn {Scheme Procedure} draw-sprite @var{texture} @var{region} + [#:scale] [#:rotation] [#:blend-mode alpha] [#:texture-region] + [#:shader] + +@end deffn + +It's not uncommon to need to draw hundreds or thousands of sprites +each frame. However, GPUs (graphics processing units) are tricky +beasts that prefer to be sent few, large chunks of data to render +rather than many, small chunks. Using @code{draw-sprite} on its own +will involve at least one GPU call @emph{per sprite}, which will +quickly lead to poor performance. To deal with this, a technique +known as ``sprite batching'' can be used. Instead of drawing each +sprite immediately, the sprite batch will build up a large of buffer +of sprites to draw and defer rendering until the last possible moment. +Batching isn't a panacea, though. Batching only works if the sprites +being drawn share as much in common as possible. Every time you draw +a sprite with a different texture or blend mode, the batch will be +sent off to the GPU. Therefore, batching is most useful if you +minimize such changes. A good strategy for reducing texture changes +is to stuff many bitmaps into a single image file and create a +``texture atlas'' (@pxref{Textures}) to access the sub-images within. + +Taking advantage of sprite batching in Chickadee is easy, just wrap +the code that is calling @code{draw-sprite} a lot in the +@code{with-batched-sprites} form. + +@deffn {Scheme Syntax} with-batched-sprites @var{body} @dots{} +Use batched rendering for all @code{draw-sprite} calls within +@var{body}. +@end deffn + +With a basic sprite abstraction in place, it's possible to build other +abstractions on top of it. One such example is the ``nine patch''. A +nine patch is a sprite that can be rendered at various sizes without +becoming distorted. This is achieved by diving up the sprite into +nine regions: + +@itemize +@item +the center, which can be scaled horizontally and vertically +@item +the four corners, which can never be scaled +@item +the left and right sides, which can be scaled vertically +@item +the top and bottom sides, which can be scaled horizontally +@end itemize + +The one caveat is that the bitmap regions must be designed in such a +way so that they are not distorted when stretched along the affected +axes. For example, that means that the top and bottom sides could +have varying colored pixels vertically, but not horizontally. + +The most common application of this technique is for graphical user +interface widgets like buttons and dialog boxes. By using a nine +patch, they can be rendered at any size without unappealing scaling +artifacts. + +@deffn {Scheme Procedure} draw-nine-patch @var{texture} @var{region} + [#:margin 0] [#:top-margin margin] [#:bottom-margin margin] + [#:left-margin margin] [#:right-margin margin] + [#:texture-region] [#:scale] [#:rotation] [#:blend-mode alpha] + [#:shader] + +Draw a nine patch sprite. A nine patch sprite renders @var{texture} +as a @var{width} x @var{height} rectangle whose stretchable areas are +defined by the given margin measurements @var{top-margin}, +@var{bottom-margin}, @var{left-margin}, and @var{right-margin}. The +@var{margin} argument may be used to configure all four margins at +once. + +Refer to @code{draw-sprite} (@pxref{Sprites}) for information about +the other arguments. +@end deffn + +@node Lines and Shapes +@subsection Lines and Shapes + +@node Fonts +@subsection Fonts + +Unlike the traditional TrueType font format that many are accustomed +to, Chickadee loads and renders bitmap fonts in the +@url{http://www.angelcode.com/products/bmfont/doc/file_format.html, +Angel Code format}. But why use this seemingly obscure format? It's +easy to find TTFs but not easy to find FNTs (the canonical file +extension used for Angel Code fonts) and bitmap fonts don't scale +well. The reason is efficiency. + +If all of the glyphs of a font are pre-rendered and packed into an +image file then it becomes possible to use a texture atlas +(@pxref{Textures}) and a sprite batch (@pxref{Sprites}) when +rendering, which is a more efficient way to render fonts than using, +say, @url{https://www.libsdl.org/projects/SDL_ttf/, SDL_ttf} or other +solutions that involve using the FreeType library directly. + +Now what about scaling? In libraries that use TTF fonts, one must +choose the size that the glyphs will be rasterized at up front. To +use @code{n} sizes of the same font, one must load @code{n} variants +of that font. If the size of the text is dynamic, some kind of +texture scaling algorithm must be used and the text will inevitably +look blurry. At first glance, using bitmap fonts seem to have an even +worse issue. Instead of just loading the same font @code{n} times at +different sizes, one would need to generate @code{n} image files for +each font size needed. This is where the ``signed distance field'' +rendering technique comes in. Introduced by +@url{http://www.valvesoftware.com/.../2007/SIGGRAPH2007_AlphaTestedMagnification.pdf, +Valve} in 2007, signed distance field fonts can be efficiently stored +in a bitmap and be rendered at arbitrary scale factors with good +results. Chickadee can render both traditional bitmap fonts and +signed distance field fonts. + +While Chickadee does not yet offer a tool for converting TTF fonts +into FNT fonts, tools such as +@url{https://github.com/libgdx/libgdx/wiki/Hiero, Hiero} may be used +in the meantime. + +The following procedures can be found in the @code{(chickadee render +font)} module. + +@deffn {Scheme Procedure} load-font @var{file} +Load the Angel Code formatted XML document in @var{file} and return a +new font object. +@end deffn + +@deffn {Scheme Procedure} font? @var{obj} +Return @code{#t} if @var{obj} is a font object. +@end deffn + +@deffn {Scheme Procedure} font-face @var{font} +Return the name of @var{font}. +@end deffn + +@deffn {Scheme Procedure} font-line-height @var{font} +Return the line height of @var{font}. +@end deffn + +@deffn {Scheme Procedure} font-line-height @var{font} +Return the line height of @var{font}. +@end deffn + +@deffn {Scheme Procedure} font-bold? @var{font} +Return @code{#t} if @var{font} is a bold font. +@end deffn + +@deffn {Scheme Procedure} font-italic? @var{font} +Return @code{#t} if @var{font} is an italicized font. +@end deffn + +@deffn {Scheme Procedure} draw-text @var{font} @var{text} @var{position} + [#:scale] [#:rotation] [#:blend-mode] + +Draw the string @var{text} with the first character starting at +@var{position} using @var{font}. + +@example +(draw-text font "Hello, world!" (vec2 128.0 128.0)) +@end example + +Refer to @code{draw-sprite} (@pxref{Sprites}) for information about +the other arguments. +@end deffn + @node Blending and Depth Testing @subsection Blending and Depth Testing -- cgit v1.2.3