/** * @file draw.h * @brief Declares the public draw API. * * Immediate-mode plotting against whichever renderer the caller hands in. This * is the shape a BASIC-style graphics vocabulary needs -- DRAW, BOX, CIRCLE, * PAINT, SSHAPE and GSHAPE all say "put this on the screen now" rather than * "add this to the scene" -- and it sits alongside the actor and tilemap * rendering rather than replacing it. * * Every entry point takes its color as an argument instead of reading a * current-color global. A caller that has a notion of a current color (a BASIC * COLOR statement, say) already owns that state and does not need the library * to keep a second copy that can disagree with it. The renderer's own draw * color is saved and restored around each call, so drawing a line never changes * what the next SDL_RenderClear() paints. */ #ifndef _DRAW_H_ #define _DRAW_H_ #include #include #include #include /** * @brief Spans akgl_draw_flood_fill() will hold while walking a region. * * The fill keeps a fixed stack of horizontal runs still to be examined rather * than recursing per pixel. A region complicated enough to need more than this * many pending runs at once reports AKERR_OUTOFBOUNDS instead of overflowing; * an ordinary convex or moderately concave shape needs a few dozen. */ #define AKGL_DRAW_MAX_FLOOD_SPANS 4096 /** * @brief Draw background. * @param w Destination width. * @param h Destination height. */ void akgl_draw_background(int w, int h); /** * @brief Plot a single pixel. * @param self Backend or object instance to operate on. * @param x Horizontal destination coordinate. * @param y Vertical destination coordinate. * @param color Color to draw with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_point(akgl_RenderBackend *self, float32_t x, float32_t y, SDL_Color color); /** * @brief Draw a line between two points. * @param self Backend or object instance to operate on. * @param x1 Horizontal coordinate of the first endpoint. * @param y1 Vertical coordinate of the first endpoint. * @param x2 Horizontal coordinate of the second endpoint. * @param y2 Vertical coordinate of the second endpoint. * @param color Color to draw with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_line(akgl_RenderBackend *self, float32_t x1, float32_t y1, float32_t x2, float32_t y2, SDL_Color color); /** * @brief Draw the outline of a rectangle. * @param self Backend or object instance to operate on. * @param rect Rectangle to outline. * @param color Color to draw with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_rect(akgl_RenderBackend *self, SDL_FRect *rect, SDL_Color color); /** * @brief Fill a rectangle. * @param self Backend or object instance to operate on. * @param rect Rectangle to fill. * @param color Color to draw with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_filled_rect(akgl_RenderBackend *self, SDL_FRect *rect, SDL_Color color); /** * @brief Draw the outline of a circle. * * SDL3 has no circle primitive, so this plots one with the midpoint circle * algorithm -- integer arithmetic, eight-way symmetry, one pass per octant. A * radius of zero draws the center pixel and nothing else. * * @param self Backend or object instance to operate on. * @param x Horizontal coordinate of the center. * @param y Vertical coordinate of the center. * @param radius Circle radius in pixels. * @param color Color to draw with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_circle(akgl_RenderBackend *self, float32_t x, float32_t y, float32_t radius, SDL_Color color); /** * @brief Flood the connected region containing one pixel with a color. * * SDL3 has no flood fill either, and unlike the shape primitives it cannot be * done on the GPU side: the region is defined by what is already on the screen. * This reads the render target back, walks the region on the CPU with a * bounded span stack, and blits the result over the area it touched. * * Filling a region that already holds @p color is a no-op rather than an error. * A seed outside the render target reports AKERR_OUTOFBOUNDS. * * @param self Backend or object instance to operate on. * @param x Horizontal coordinate of the seed pixel. * @param y Vertical coordinate of the seed pixel. * @param color Color to fill with. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_flood_fill(akgl_RenderBackend *self, int x, int y, SDL_Color color); /** * @brief Read a rectangle of the render target into a surface. * * The save half of SSHAPE/GSHAPE. When `*dest` is `NULL` the function allocates * the surface and the caller owns it from then on -- release it with * SDL_DestroySurface(). When `*dest` already points at a surface of exactly * @p src's dimensions the pixels are copied into it instead, so a caller * saving the same region repeatedly does not churn allocations. * * @param self Backend or object instance to operate on. * @param src Rectangle of the render target to read. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_copy_region(akgl_RenderBackend *self, SDL_Rect *src, SDL_Surface **dest); /** * @brief Draw a saved surface back onto the render target. * * The restore half of SSHAPE/GSHAPE, taking what akgl_draw_copy_region() * produced. The surface is not consumed and may be pasted as many times as the * caller likes. * * @param self Backend or object instance to operate on. * @param src Surface to draw. * @param x Horizontal destination coordinate. * @param y Vertical destination coordinate. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKGL_ERR_SDL When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_paste_region(akgl_RenderBackend *self, SDL_Surface *src, float32_t x, float32_t y); #endif //_DRAW_H_