Skip to content
RobLoachPublic

About

Header-only CPU graphics library for C, with a focus on ease of use.

Topics

Resources

Stars

45 stars

Watchers

2 watching

Forks

Repository files navigation

pntr

Header-only CPU graphics library for C99 or C++, with a focus on ease-of-use.

Usage

#define PNTR_PIXELFORMAT_RGBA
#define PNTR_IMPLEMENTATION
#include "pntr.h"

int main() {
    pntr_image* image = pntr_new_image(200, 200);
    pntr_draw_circle_fill(image, 100, 100, 80, PNTR_RED);
    pntr_save_image(image, "output.png");
    pntr_unload_image(image);

    return 0;
}

Examples

Example: Image Example: Shapes Example: Fonts Example: Sprite

Features

  • Draw rectangles, circles, ellipses, triangles, lines, arcs, etc
  • RGBA or ARGB pixel bit order
  • Clipping
  • Load and save images (PNG, BMP, and JPEG with PNTR_ENABLE_JPEG)
  • Draw sprites with scaling and rotation
  • Alpha-blending, alpha masks, invert, brightness, etc
  • Font rendering (TTF, BMF, TTY)
  • UTF-8
  • Documentation

Integrations

Name Description
pntr_app Application wrapper for running the same pntr code in raylib, SDL, Web, libretro, or in a CLI
pntr_assetsys Load pntr assets from .zip files with assetsys.h
pntr_physfs Load pntr assets from .zip files with PhysicsFS
pntr_nuklear Nuklear immediate-mode graphical user interface for pntr
pntr_aseprite Use Aseprite animated sprites in pntr
pntr_tiled Display Tiled 2D level editor maps in pntr
pntr_portablegl Use the OpenGL-esque software rendering library, PortableGL, in pntr
pntr_doom Play DOOM via PureDOOM rendered through pntr
pntr_pixelfont Additional pixel fonts outside of the default
zig_pntr Zig wrapper for pntr

API

In order to use pntr, define PNTR_IMPLEMENTATION in one of your .c files before including pntr.h.

#define PNTR_IMPLEMENTATION
#include "pntr.h"

Version

pntr.h reports its own version, so you can display it or compile against a specific release:

printf("pntr %s\n", PNTR_VERSION); // "0.1.0"

#if PNTR_VERSION_MAJOR > 0 || (PNTR_VERSION_MAJOR == 0 && PNTR_VERSION_MINOR >= 1)
    pntr_color color = pntr_image_get_color_bilinear(image, 1.5f, 1.5f);
#endif
Define Description
PNTR_VERSION The version as a "MAJOR.MINOR.PATCH" string
PNTR_VERSION_MAJOR The major version number
PNTR_VERSION_MINOR The minor version number
PNTR_VERSION_PATCH The patch version number

Configuration

You can modify how pntr functions based on the following defines:

Define Description
PNTR_IMPLEMENTATION Define this in one of your .c or .cpp files before including pntr.h
PNTR_PIXELFORMAT_RGBA Use the RGBA format
PNTR_PIXELFORMAT_ARGB Use the ARGB pixel format
PNTR_ENABLE_DEFAULT_FONT Enables the default 8x8 pixel font
PNTR_ENABLE_JPEG Enables JPEG image loading, when the active image backend supports it
PNTR_ENABLE_MATH Enables use of C's standard math.h linked library, rather than using the built in math functions
PNTR_ENABLE_TTF Enables support for loading TrueType fonts
PNTR_ENABLE_UTF8 Enables UTF-8 support for font loading and text rendering
PNTR_ENABLE_VARGS Adds support for functions that require variadic arguments, like pntr_draw_text_ex()
PNTR_ERROR_STORAGE The storage class that holds the last error reported by pntr_set_error(). Defaults to static, which every thread shares. Define it as a thread-local storage class, like static _Thread_local, to give each thread an error of its own
PNTR_LOAD_FILE Callback to use when asked to load a file in pntr_load_file(). By default, will use stdio.h.
PNTR_LOAD_IMAGE_FROM_MEMORY Callback to use when loading an image from memory via pntr_load_image_from_memory(). By default, will use stb_image
PNTR_SAVE_FILE Callback to use when saving a file via pntr_save_file(). By default, uses stdio.h
PNTR_SAVE_IMAGE_TO_MEMORY Callback to use when saving an image to memory via pntr_save_image_to_memory(). By default, will use stb_image_write
PNTR_NO_ALPHABLEND Skips alpha blending when drawing pixels
PNTR_NO_BMP Drops BMP image loading, saving about 6.5kb. Saving BMP is unaffected
PNTR_NO_STDIO Will disable the standard file loading/saving calls for PNTR_LOAD_FILE and PNTR_SAVE_FILE
PNTR_NO_SAVE_IMAGE Disables the default behavior of image saving
PNTR_NO_LOAD_IMAGE Disables the default behavior of image loading
PNTR_NO_CUTE_PNG_IMPLEMENTATION Skips defining CUTE_PNG_IMPLEMENTATION. Useful if you're using cute_png elsewhere
PNTR_NO_STB_TRUETYPE_IMPLEMENTATION Skips defining STB_TRUETYPE_IMPLEMENTATION. Useful if you're using stb_truetype elsewhere
PNTR_NO_STB_IMAGE_WRITE_IMPLEMENTATION Skips defining STB_IMAGE_WRITE_IMPLEMENTATION. useful if you're using stb_image_write elsewhere
PNTR_NO_STB_IMAGE_IMPLEMENTATION Skips defining STB_IMAGE_IMPLEMENTATION. useful if you're using stb_image_write elsewhere

Images

pntr_image* pntr_new_image(int width, int height);
pntr_image* pntr_gen_image_color(int width, int height, pntr_color color);
pntr_image* pntr_gen_image_gradient(int width, int height, pntr_color topLeft, pntr_color topRight, pntr_color bottomLeft, pntr_color bottomRight);
pntr_image* pntr_image_copy(pntr_image* image);
pntr_image* pntr_image_from_image(pntr_image* image, int x, int y, int width, int height);
pntr_image* pntr_image_subimage(pntr_image* image, int x, int y, int width, int height);
void pntr_unload_image(pntr_image* image);
pntr_image* pntr_load_image(const char* fileName);
pntr_image* pntr_load_image_from_memory(pntr_image_type type, const unsigned char* fileData, unsigned int dataSize);
pntr_image* pntr_image_from_pixelformat(const void* data, int width, int height, pntr_pixelformat pixelFormat);
bool pntr_save_image(pntr_image* image, const char* fileName);
unsigned char* pntr_save_image_to_memory(pntr_image* image, pntr_image_type type, unsigned int* dataSize);
void* pntr_image_to_pixelformat(pntr_image* image, unsigned int* dataSize, pntr_pixelformat pixelFormat);
int pntr_get_pixel_data_size(int width, int height, pntr_pixelformat pixelFormat);
pntr_image_type pntr_get_file_image_type(const char* filePath);

Drawing

void pntr_clear_background(pntr_image* image, pntr_color color);
void pntr_draw_point(pntr_image* dst, int x, int y, pntr_color color);
void pntr_draw_point_vec(pntr_image* dst, pntr_vector* point, pntr_color color);
void pntr_draw_points(pntr_image* dst, pntr_vector* points, int pointsCount, pntr_color color);
void pntr_draw_line(pntr_image* dst, int startPosX, int startPosY, int endPosX, int endPosY, pntr_color color);
void pntr_draw_line_vec(pntr_image* dst, pntr_vector start, pntr_vector end, pntr_color color);
void pntr_draw_line_aa(pntr_image* dst, int startPosX, int startPosY, int endPosX, int endPosY, pntr_color color);
void pntr_draw_line_thick(pntr_image* dst, int startPosX, int startPosY, int endPosX, int endPosY, int thickness, pntr_color color);
void pntr_draw_line_thick_vec(pntr_image* dst, pntr_vector start, pntr_vector end, int thickness, pntr_color color);
void pntr_draw_line_horizontal(pntr_image* dst, int posX, int posY, int width, pntr_color color);
void pntr_draw_line_horizontal_thick(pntr_image* dst, int posX, int posY, int width, int thickness, pntr_color color);
void pntr_draw_line_vertical(pntr_image* dst, int posX, int posY, int height, pntr_color color);
void pntr_draw_line_vertical_thick(pntr_image* dst, int posX, int posY, int height, int thickness, pntr_color color);
void pntr_draw_line_curve(pntr_image* dst, pntr_vector point1, pntr_vector point2, pntr_vector point3, pntr_vector point4, int segments, pntr_color color);
void pntr_draw_line_curve_thick(pntr_image* dst, pntr_vector point1, pntr_vector point2, pntr_vector point3, pntr_vector point4, int segments, int thickness, pntr_color color);
void pntr_draw_rectangle(pntr_image* dst, int posX, int posY, int width, int height, pntr_color color);
void pntr_draw_rectangle_rec(pntr_image* dst, pntr_rectangle rec, pntr_color color);
void pntr_draw_rectangle_fill(pntr_image* dst, int posX, int posY, int width, int height, pntr_color color);
void pntr_draw_rectangle_fill_rec(pntr_image* dst, pntr_rectangle rect, pntr_color color);
void pntr_draw_rectangle_thick(pntr_image* dst, int posX, int posY, int width, int height, int thickness, pntr_color color);
void pntr_draw_rectangle_thick_rec(pntr_image* dst, pntr_rectangle rect, int thickness, pntr_color color);
void pntr_draw_rectangle_gradient(pntr_image* dst, int x, int y, int width, int height, pntr_color topLeft, pntr_color topRight, pntr_color bottomLeft, pntr_color bottomRight);
void pntr_draw_rectangle_gradient_rec(pntr_image* dst, pntr_rectangle rect, pntr_color topLeft, pntr_color topRight, pntr_color bottomLeft, pntr_color bottomRight);
void pntr_draw_rectangle_rounded(pntr_image* dst, int x, int y, int width, int height, int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius, pntr_color color);
void pntr_draw_rectangle_rounded_fill(pntr_image* dst, int x, int y, int width, int height, int cornerRadius, pntr_color color);
void pntr_draw_rectangle_thick_rounded(pntr_image* dst, int x, int y, int width, int height, int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius, int thickness, pntr_color color);
void pntr_draw_circle(pntr_image* dst, int centerX, int centerY, int radius, pntr_color color);
void pntr_draw_circle_fill(pntr_image* dst, int centerX, int centerY, int radius, pntr_color color);
void pntr_draw_circle_thick(pntr_image* dst, int centerX, int centerY, int radius, int thickness, pntr_color color);
void pntr_draw_ellipse(pntr_image* dst, int centerX, int centerY, int radiusX, int radiusY, pntr_color color);
void pntr_draw_ellipse_fill(pntr_image* dst, int centerX, int centerY, int radiusX, int radiusY, pntr_color color);
void pntr_draw_ellipse_thick(pntr_image* dst, int centerX, int centerY, int radiusX, int radiusY, int thickness, pntr_color color);
void pntr_draw_triangle(pntr_image* dst, int x1, int y1, int x2, int y2, int x3, int y3, pntr_color color);
void pntr_draw_triangle_vec(pntr_image* dst, pntr_vector point1, pntr_vector point2, pntr_vector point3, pntr_color color);
void pntr_draw_triangle_fill(pntr_image* dst, int x1, int y1, int x2, int y2, int x3, int y3, pntr_color color);
void pntr_draw_triangle_fill_vec(pntr_image* dst, pntr_vector point1, pntr_vector point2, pntr_vector point3, pntr_color color);
void pntr_draw_triangle_thick(pntr_image* dst, int x1, int y1, int x2, int y2, int x3, int y3, int thickness, pntr_color color);
void pntr_draw_triangle_thick_vec(pntr_image* dst, pntr_vector point1, pntr_vector point2, pntr_vector point3, int thickness, pntr_color color);
void pntr_draw_arc(pntr_image* dst, int centerX, int centerY, float radius, float startAngle, float endAngle, int segments, pntr_color color);
void pntr_draw_arc_fill(pntr_image* dst, int centerX, int centerY, float radius, float startAngle, float endAngle, int segments, pntr_color color);
void pntr_draw_arc_thick(pntr_image* dst, int centerX, int centerY, float radius, float startAngle, float endAngle, int segments, int thickness, pntr_color color);
void pntr_draw_polygon(pntr_image* dst, pntr_vector* points, int numPoints, pntr_color color);
void pntr_draw_polygon_fill(pntr_image* dst, pntr_vector* points, int numPoints, pntr_color color);
void pntr_draw_polygon_thick(pntr_image* dst, pntr_vector* points, int numPoints, int thickness, pntr_color color);
void pntr_draw_polyline(pntr_image* dst, pntr_vector* points, int numPoints, pntr_color color);
void pntr_draw_polyline_thick(pntr_image* dst, pntr_vector* points, int numPoints, int thickness, pntr_color color);
void pntr_draw_image(pntr_image* dst, pntr_image* src, int posX, int posY);
void pntr_draw_image_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, int posX, int posY);
void pntr_draw_image_tint(pntr_image* dst, pntr_image* src, int posX, int posY, pntr_color tint);
void pntr_draw_image_tint_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, int posX, int posY, pntr_color tint);
void pntr_draw_image_rotated(pntr_image* dst, pntr_image* src, int posX, int posY, float degrees, float offsetX, float offsetY, pntr_filter filter);
void pntr_draw_image_rotated_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, int posX, int posY, float degrees, float offsetX, float offsetY, pntr_filter filter);
void pntr_draw_image_flipped(pntr_image* dst, pntr_image* src, int posX, int posY, bool flipHorizontal, bool flipVertical, bool flipDiagonal);
void pntr_draw_image_flipped_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRec, int posX, int posY, bool flipHorizontal, bool flipVertical, bool flipDiagonal);
void pntr_draw_image_scaled(pntr_image* dst, pntr_image* src, int posX, int posY, float scaleX, float scaleY, float offsetX, float offsetY, pntr_filter filter, pntr_color tint);
void pntr_draw_image_scaled_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, int posX, int posY, float scaleX, float scaleY, float offsetX, float offsetY, pntr_filter filter, pntr_color tint);
void pntr_draw_image_dest_rec(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, pntr_rectangle dstRect, pntr_filter filter, pntr_color tint);
void pntr_draw_image_rotozoom(pntr_image* dst, pntr_image* src, pntr_rectangle srcRect, int posX, int posY, float rotation, float scaleX, float scaleY, float originX, float originY, pntr_filter filter, pntr_color tint);
void pntr_draw_text(pntr_image* dst, pntr_font* font, const char* text, int posX, int posY, pntr_color tint);
void pntr_draw_text_len(pntr_image* dst, pntr_font* font, const char* text, int textLength, int posX, int posY, pntr_color tint);
void pntr_draw_text_aligned(pntr_image* dst, pntr_font* font, const char* text, int posX, int posY, pntr_text_align align, pntr_color tint);
void pntr_draw_text_wrapped(pntr_image* dst, pntr_font* font, const char* text, int posX, int posY, int maxWidth, pntr_color tint);
void pntr_draw_text_ex(pntr_image* dst, pntr_font* font, int posX, int posY, pntr_color tint, int maxlen, const char* text, ...);
void pntr_draw_point_unsafe(pntr_image* dst, int x, int y, pntr_color color);
void pntr_put_horizontal_line_unsafe(pntr_image* dst, int posX, int posY, int width, pntr_color color);

The _unsafe functions perform no bounds or clipping checks, so they will write outside the image if given coordinates that are out of range. Only use them when you have already confirmed the coordinates are within the image's clip region.

Bounds

Whether a shape covers its far edge depends on how you describe the shape, not on whether it is an outline or a fill:

  • Shapes described by their points cover every point you pass. pntr_draw_line(image, 0, 0, 10, 0, color) paints 11 pixels, from x = 0 through x = 10, including the degenerate case of a line whose two endpoints are the same pixel. The same holds for pntr_draw_line_aa(), pntr_draw_line_thick(), pntr_draw_line_curve(), pntr_draw_polyline(), pntr_draw_polygon() and pntr_draw_triangle(). It also holds for the matching fills, so pntr_draw_polygon_fill() and pntr_draw_triangle_fill() cover the whole bounding box of the points they are given, and therefore line up with the outline drawn from the same points. A radius behaves as a point too: pntr_draw_circle_fill(image, 50, 50, 10, color) is 21 pixels across and 21 pixels tall, and covers every pixel of the outline that pntr_draw_circle() draws for the same center and radius. pntr_draw_ellipse_fill() and pntr_draw_ellipse() register the same way. That includes the degenerate radii: a radius of one is three pixels across, a radius of zero is the center point on its own, and an ellipse with a radius of zero on one axis is the straight line through its center.
  • Shapes described by an extent stop short of the far edge. pntr_draw_rectangle(image, x, y, width, height, color) paints columns x through x + width - 1 and rows y through y + height - 1, so width and height are a count of pixels rather than a second coordinate. pntr_draw_rectangle_fill(), pntr_draw_rectangle_rounded(), pntr_draw_line_horizontal(), pntr_draw_line_vertical(), and the clip region of pntr_image_set_clip() all read their sizes the same way.

A rounded rectangle therefore occupies exactly the same pixels as a plain rectangle of the same x, y, width and height, and a thick line is the same length as the thin line through the same two endpoints.

Colors

pntr_color pntr_new_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
pntr_color pntr_get_color(unsigned int hexValue);
unsigned char pntr_color_r(pntr_color color);
unsigned char pntr_color_g(pntr_color color);
unsigned char pntr_color_b(pntr_color color);
unsigned char pntr_color_a(pntr_color color);
void pntr_color_set_r(pntr_color* color, unsigned char r);
void pntr_color_set_g(pntr_color* color, unsigned char g);
void pntr_color_set_b(pntr_color* color, unsigned char b);
void pntr_color_set_a(pntr_color* color, unsigned char a);
pntr_color pntr_image_get_color(pntr_image* image, int x, int y);
pntr_color pntr_image_get_color_bilinear(pntr_image* image, float x, float y);
pntr_color pntr_color_tint(pntr_color color, pntr_color tint);
void pntr_image_color_tint(pntr_image* image, pntr_color color);
pntr_color pntr_color_fade(pntr_color color, float alpha);
void pntr_image_color_fade(pntr_image* image, float alpha);
pntr_color pntr_color_brightness(pntr_color color, float factor);
void pntr_image_color_brightness(pntr_image* image, float factor);
pntr_color pntr_color_contrast(pntr_color color, float contrast);
void pntr_image_color_contrast(pntr_image* image, float contrast);
pntr_color pntr_color_invert(pntr_color color);
void pntr_image_color_invert(pntr_image* image);
pntr_color pntr_color_grayscale(pntr_color color);
void pntr_image_color_grayscale(pntr_image* image);
void pntr_image_color_replace(pntr_image* image, pntr_color color, pntr_color replace);
pntr_color pntr_color_alpha_blend(pntr_color dst, pntr_color src);
pntr_color pntr_color_bilinear_interpolate(pntr_color color00, pntr_color color01, pntr_color color10, pntr_color color11, float coordinateX, float coordinateY);
pntr_color pntr_get_pixel_color(void* srcPtr, pntr_pixelformat srcPixelFormat);
void pntr_set_pixel_color(void* dstPtr, pntr_pixelformat dstPixelFormat, pntr_color color);

Fonts

pntr_font* pntr_load_font_default(void);
pntr_font* pntr_load_font_bmf(const char* fileName, const char* characters);
pntr_font* pntr_load_font_bmf_from_image(pntr_image* image, const char* characters);
pntr_font* pntr_load_font_bmf_from_memory(const unsigned char* fileData, unsigned int dataSize, const char* characters);
pntr_font* pntr_load_font_tty(const char* fileName, int glyphWidth, int glyphHeight, const char* characters);
pntr_font* pntr_load_font_tty_from_image(pntr_image* image, int glyphWidth, int glyphHeight, const char* characters);
pntr_font* pntr_load_font_tty_from_memory(const unsigned char* fileData, unsigned int dataSize, int glyphWidth, int glyphHeight, const char* characters);
pntr_font* pntr_load_font_ttf(const char* fileName, int fontSize);
pntr_font* pntr_load_font_ttf_from_memory(const unsigned char* fileData, unsigned int dataSize, int fontSize);
pntr_font* pntr_font_copy(pntr_font* font);
pntr_font* pntr_font_scale(pntr_font* font, float scaleX, float scaleY, pntr_filter filter);
void pntr_unload_font(pntr_font* font);
int pntr_measure_text(pntr_font* font, const char* text);
pntr_vector pntr_measure_text_ex(pntr_font* font, const char* text, int textLength);
pntr_image* pntr_gen_image_text(pntr_font* font, const char* text, pntr_color tint, pntr_color backgroundColor);

Image Operations

pntr_image* pntr_image_resize(pntr_image* image, int newWidth, int newHeight, pntr_filter filter);
pntr_image* pntr_image_scale(pntr_image* image, float scaleX, float scaleY, pntr_filter filter);
bool pntr_image_resize_canvas(pntr_image* image, int newWidth, int newHeight, int offsetX, int offsetY, pntr_color fill);
pntr_image* pntr_image_rotate(pntr_image* image, float degrees, pntr_filter filter);
void pntr_image_flip(pntr_image* image, bool horizontal, bool vertical);
bool pntr_image_crop(pntr_image* image, int x, int y, int width, int height);
void pntr_image_alpha_crop(pntr_image* image, float threshold);
pntr_rectangle pntr_image_alpha_border(pntr_image* image, float threshold);
void pntr_image_alpha_mask(pntr_image* image, pntr_image* alphaMask, int posX, int posY);
pntr_rectangle pntr_image_get_clip(pntr_image* image);
void pntr_image_set_clip(pntr_image* image, int x, int y, int width, int height);
void pntr_image_set_clip_rec(pntr_image* image, pntr_rectangle clip);
void pntr_image_reset_clip(pntr_image* image);

File I/O

unsigned char* pntr_load_file(const char *fileName, unsigned int *bytesRead);
void pntr_unload_file(unsigned char* fileData);
const char* pntr_load_file_text(const char *fileName);
void pntr_unload_file_text(const char* text);
bool pntr_save_file(const char *fileName, const void *data, unsigned int bytesToWrite);

Error Handling

void* pntr_set_error(pntr_error error);
const char* pntr_get_error(void);
pntr_error pntr_get_error_code(void);

Memory

void* pntr_load_memory(size_t size);
void pntr_unload_memory(void* pointer);
void* pntr_memory_copy(void* destination, void* source, size_t size);

Development

To build the tests and examples, use CMake:

# Set up the build files.
cmake -B build

# Build the tests and examples.
cmake --build build

# Run the tests
ctest --test-dir build -V

Documentation

To build the documentation, use Doxygen...

doxygen .Doxyfile

To publish the documentation, use Node.js...

npm run docs

Acknowledgements

License

Unless stated otherwise, all works are:

... and licensed under:

About

Header-only CPU graphics library for C, with a focus on ease of use.

Topics

Resources

Stars

45 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages