The TFB Graphics Libraries Initial documentation by Michael Martin, 4 Feb 2003 The graphics system in UQM has three major subsystems: - The "legacy" system, which most of the core code uses. This involves the foo_blt () routines in 3do_blt.c, and the data types CONTEXT, FRAME, DRAWABLE, and possibly others. I'm less familiar with this code, and want to eradicate as much of it as I can, but for now, its lowest level has been rewritten as direct calls to: - The TFB_Draw* commands, documented below in great detail. These routines deal with the datatype TFB_Image, and the more primitive TFB_Canvas. They also support drawing to one of several 'screens', but since only one thread should be allowed to touch the screen, the TFB_DrawScreen routines end up constructing inputs to: - The DCQ/DrawCommand library. This is a ring queue with commands for rendering graphics on the actual screen. It interacts to some degree with the CONTEXT datatype, but otherwise is defined entirely in terms of TFB_Images and TFB_Canvases. THE LEGACY LIBRARY -------------------- The datatypes the code uses directly are CONTEXT, FRAME, and FONT, all of which are really pointers to void. Pointers to those are PCONTEXT, PFRAME, and PFONT. Then there's DRAWABLE, which is a DWORD, and its pointer type PDRAWABLE. (These are defined in sc2code/libs/gfxlib.h.) I'm not sure how DRAWABLE values are transformed into actual drawable entities. The full structures for these are in various files in sc2code/libs/graphics. context.h: defines CONTEXT_DESC and PCONTEXT_DESC (and the equivalent CONTEXTPTR -- insert various sorts of incomprenshible muttering here), display.h: defines a DISPLAY_INTERFACE and PDISPLAY_INTERFACE type (as well as a global _pCurDisplay). drawable.h: defines FRAME_DESC and DRAWABLE_DESC, and the pointer types PFRAME_DESC and PDRAWABLE_DESC. FRAME_DESC has a TFB_Image pointer as a member. DRAWABLE_DESC currently still uses a rather annoying technique where the last member of a struct is a 1-element array, more memory than that is actually allocated, and the array's bounds are deliberately overflowed to get at multiple frames. font.h: defines FONT_DESC and PFONT_DESC. (Details on how all these data types work is forthcoming.) THE TFB_DRAW LIBRARY ---------------------- The TFB_Draw commands have a single header file: sc2code/libs/graphics/tfb_draw.h. This file declares the following data types: SCREEN: This is an enum, naming the various screens that the DrawCmd library can draw to. Valid values at present are TFB_SCREEN_MAIN, TFB_SCREEN_EXTRA, and TFB_SCREEN_TRANSITION. These correspond to various objects that are of type TFB_Canvas. (The maximal number of screens is provided by a bogus last element, TFB_GFX_NUMSCREENS. Keep that as the last element and the allocators will operate properly regardless of any screens you may later want to add.) TFB_Canvas: This is, for the purposes of most of the code, a void pointer. The implementations of TFB_DrawCanvas commands cast them to the appropriate type. (The only implementation of these commands casts them to SDL_Surface*.) TFB_Palette: Four UBYTES, r, g, b, and 'unused'. This is designed at present to be directly castable to SDL_Color, which most things do. We should probably do something about that at some point. TFB_Image: The most important image structure. This has two TFB_Canvases (one for the 'core' image, one for a scaled version of it), a pointer to a TFB_Palette array, a colormap index, a scaling constant, a Mutex from the threading library (to ensure internal consistency if multiple threads are doing stuff), and a 'dirty bit' which means that, if the image is scaled, the ScaledImg needs to be recomputed. TFB_DrawScreen -------------- When you wish to draw graphics directly on the screen, you call these routines, which enqueue the DrawCommands: ---- void TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, int r, int g, int b, SCREEN dest); Draws a line from (x1, y1)-(x2, y2) of a color specified by r, g, and b on the specified screen. We have a known bug here in that if a corner of one of these lines is outside of the context's clipping rectangle, the slope of the line may change. ---- void TFB_DrawScreen_Rect (PRECT rect, int r, int g, int b, SCREEN dest); Draws a (filled) rectangle with the specified color on the destination screen. PRECT is part of the legacy library. void TFB_DrawScreen_Copy (PRECT r, SCREEN src, SCREEN dest); Copies data between screens. The PRECT defines the region to copy. This can be handy in saving and restoring background information. ---- void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, BOOLEAN scaled, TFB_Palette *palette, SCREEN dest); void TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, BOOLEAN scaled, int r, int g, int b, SCREEN dest); These two routines draw images. img, x, and y are all straightforward (x and y refer to the upper left of the image), and scaled indicates whether or not the NormalImg or ScaledImg should be used, and dest names the target screen. For TFB_DrawScreen_Image, the 'palette' argument refers to a 256-element array of TFB_Palette that describes the palette to use. (The default is cached in TFB_Image itself.) Various techniques are used to cache the palette values to keep spurious palette-switch commands from flooding the DrawCmd queue. However, switching the palette many times per frame is likely to seriously degrade performance. TFB_DrawScreen_FilledImage draws every non-transparent pixel in img in the color specified by r, g, b. (Fonts and some menus do this.) ---- void TFB_DrawScreen_WaitForSignal (void); Puts this thread to sleep until all commands queued to this point are executed. Mostly used to keep from spamming the DrawCmd queue, and to ensure proper operation of the next two routines. ---- void TFB_DrawScreen_CopyToImage (TFB_Image *img, PRECT lpRect, SCREEN src); Load the pixels from the rectangle lpRect in screen src into img. If you're actually working with the pixels directly, you'll want to do a TFB_DrawScreen_WaitForSignal () to ensure the image has actually been updated. (If you're just passing it to other TFB_DrawScreen commands, that's unnecessary, because ordering within a thread is guaranteed.) ---- void TFB_DrawScreen_DeleteImage (TFB_Image *img); Deallocates all memory associated with img. This REALLY doesn't belong here. It should be a TFB_DrawImage command, with a requirement that you WaitForSignal lfirst. ---- TFB_DrawImage ------------- These routines are similar to a subset of the TFB_DrawScreen commands, except that instead of drawing on the screen at some later time, they draw directly and immediately onto a TFB_Image. The arguments all mean the same things as they did for TFB_DrawScreen. ---- void TFB_DrawImage_Line (int x1, int y1, int x2, int y2, int r, int g, int b, TFB_Image *dest); void TFB_DrawImage_Rect (PRECT rect, int r, int g, int b, TFB_Image *image); void TFB_DrawImage_Image (TFB_Image *img, int x, int y, BOOLEAN scaled, TFB_Palette *palette, TFB_Image *target); void TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, BOOLEAN scaled, int r, int g, int b, TFB_Image *target); ---- TFB_DrawCanvas -------------- These routines are, quite literally, identical in every way to the TFB_DrawImage routines, except that they draw on TFB_Canvases instead. They are defined in graphics-library-specific locations. There is, at present, only one implementation of these, in libs/graphics/sdl/canvas.c. void TFB_DrawCanvas_Line (int x1, int y1, int x2, int y2, int r, int g, int b, TFB_Canvas dest); void TFB_DrawCanvas_Rect (PRECT rect, int r, int g, int b, TFB_Canvas image); void TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, BOOLEAN scaled, TFB_Palette *palette, TFB_Canvas target); void TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, BOOLEAN scaled, int r, int g, int b, TFB_Canvas target); ---- Creation and Destruction of TFB_Images, TFB_Canvases, and TFB_Palettes ---------------------------------------------------------------------- Various commands exist for creating and destroying the TFB_Draw data types. The concept of "ownership" is critical here. If a data object owns a pointer inside of it, that pointer's referent is deallocated when the data object is deallocated. If a pointer variable owns its referent, it's permissible to delete it. TFB_Canvas and TFB_Palette are primitives. TFB_Image owns NormalImg, ScaledImg, and Palette, and will delete them when it is itself deleted. That said, here are the routines: --- TFB_Image *TFB_DrawImage_New (TFB_Canvas canvas) Creates a new TFB_Image, which the caller then owns. The caller must own the canvas, and transfers ownership of that canvas to the image. The Palette value is automatically created (and the image owns it); ScaledImg will be NULL until you scale the image and draw it to the screen. --- void TFB_DrawImage_Delete (TFB_Image *image) Deletes the image, and all non-NULL components. You must own the image you delete. --- TFB_Canvas TFB_DrawCanvas_New_TrueColor (int w, int h, BOOLEAN has_alpha); TFB_Canvas TFB_DrawCanvas_New_Paletted (int w, int h, TFB_Palette *palette, int transparent_index); These create new TFB_Canvases, which the caller will then own. Width and height are straightforward. The TrueColor variant produces Canvases with the same color depth and pixel format as the screen. The has_alpha flag indicates whether or not the canvas has an alpha channel. The Paletted variant produces 8-bit paletted canvases. The palette argument is optional (it can be NULL, in which case you'll need to set it later - TFB_Images tend to do this when drawn), as is the transparent_index (if -1, there is no transparency; otherwise, it's the index of the transparent color). --- TFB_Canvas TFB_DrawCanvas_ToScreenFormat (TFB_Canvas canvas); Returns a canvas that, if possible, matches the graphics configuration of the screen. You must own the source canvas. If the conversion is possible, it makes the conversion, deletes its argument, and returns the converted version; if conversion is not possible, the canvas is returned intact. Regardless of success or failure, the caller owns the result. --- TFB_Palette *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas); Allocates and returns a 256-entry TFB_Palette array that describes the palette of the canvas, or returns NULL if the canvas is true-color. If the result is non-NULL, the caller owns the result. The caller need not own canvas. DRAWCMD LIBRARY ----------------- Documentation yet to be written. UQM code shouldn't really mess with the DrawCmd library directly.