Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DRESsedAlarm184/LWXGL/llms.txt

Use this file to discover all available pages before exploring further.

LWXGL’s image element acts as a palette-indexed pixel canvas backed by a per-element byte buffer. Each byte in the buffer is a palette index (0–15), and the renderer blits the corresponding color from the active 16-color palette to an X11 pixmap each frame. By writing to the buffer directly or through the primitive drawing functions and then calling UpdateImage, you can achieve fully custom pixel-level rendering inside any element region.

Creating an Image Element

void CreateImage(int id, int x, int y, int w, int h);
  • id — unique element ID
  • x, y — top-left position in back-buffer coordinates
  • w, h — pixel dimensions of the canvas
When w or h is zero or negative, the dimension expands relative to the remaining back-buffer space from the given origin using the formula bb.w - x + w (where w is the original argument). Concretely:
  • w = 0 → width fills to the right edge: bb.w - x
  • w = -10 → width fills to the right edge minus 10px: bb.w - x - 10
// Full-window canvas (start at 0,0, extend to edges)
CreateImage(1, 0, 0, 0, 0);

// Canvas with a 10px margin on the right only
CreateImage(2, 0, 0, -10, 0);
CreateImage allocates two equal-sized buffers internally: data (writable) and prev (shadow copy for dirty-tracking). UpdateImage only re-pushes pixels that differ between the two, minimising X11 round-trips.

Reading and Writing Pixels

GetImageData

unsigned char* GetImageData(int id);
Returns a pointer to the writable pixel buffer. The layout is row-major: pixel at (x, y) is at index y * width + x. Each byte is a palette index 0–15.
unsigned char* pixels = GetImageData(1);
int width = /* element width */;

// Write a single white pixel at (10, 20)
pixels[20 * width + 10] = CLR_WHITE;

UpdateImage

void UpdateImage(int id);
Flushes changes from the data buffer to the X11 pixmap. Only changed pixels (compared to the internal prev shadow) are re-pushed. Call this once after a batch of pixel writes.
// Batch: draw, then flush once
ClearImage(1, CLR_BLACK);
PrimitiveCircle(1, 100, 100, 40, CLR_WHITE, CLR_BLUE);
UpdateImage(1);  // single flush

ClearImage

void ClearImage(int id, int c);
Fills the entire pixel buffer with palette index c using memset. This is the fastest way to reset the canvas.
ClearImage(1, CLR_BLACK);  // black background

Primitive Drawing Functions

All primitives write into the image element’s data buffer. Call UpdateImage after drawing to commit changes to the screen.
void PrimitiveRect(int id, int x, int y, int w, int h, int fg, int bg);
Draws a rectangle border using fg and fills the interior with bg. Pass CLR_NONE (-1) for either to skip it.When fg == -1, fg is set equal to bg before drawing, producing a solid filled block with no distinct border.
// White-bordered rectangle, blue fill
PrimitiveRect(1, 10, 10, 80, 50, CLR_WHITE, CLR_BLUE);

// Border only, no fill
PrimitiveRect(1, 10, 10, 80, 50, CLR_WHITE, CLR_NONE);

// Solid filled block, no border (fg set to bg internally when fg == -1)
PrimitiveRect(1, 10, 10, 80, 50, CLR_NONE, CLR_RED);
void PrimitiveCircle(int id, int cx, int cy, int r, int fg, int bg);
Draws a circle centered at (cx, cy) with radius r. fg is the outline color and bg is the fill color. Either may be CLR_NONE.The fill test is dx² + dy² ≤ r²; the border test is |dx² + dy² − r²| < r.
// Filled cyan circle, white outline
PrimitiveCircle(1, 100, 100, 30, CLR_WHITE, CLR_CYAN);

// Outline only
PrimitiveCircle(1, 100, 100, 30, CLR_WHITE, CLR_NONE);
void PrimitiveLine(int id, int x1, int y1, int x2, int y2, int color);
Draws a straight line between (x1, y1) and (x2, y2) using linear interpolation (DDA-style). Out-of-bounds pixels are clipped silently.
// Diagonal line across the canvas
PrimitiveLine(1, 0, 0, 199, 149, CLR_YELLOW);

// Horizontal line
PrimitiveLine(1, 0, 75, 199, 75, CLR_LGRAY);
void PrimitiveTriangle(int id,
                        int x1, int y1,
                        int x2, int y2,
                        int x3, int y3,
                        int fg, int bg);
Fills the triangle defined by the three vertices using an edge-function rasterizer, then draws the three outline edges with PrimitiveLine. Pass CLR_NONE for fg or bg to skip the outline or fill respectively.
// Filled red triangle with white outline
PrimitiveTriangle(1, 100, 10, 10, 140, 190, 140,
                  CLR_WHITE, CLR_RED);

// Fill only
PrimitiveTriangle(1, 100, 10, 10, 140, 190, 140,
                  CLR_NONE, CLR_MAGENTA);
void PrimitiveSprite(int id, int sx, int sy, int color,
                     const char* sprite, int scale);
Draws a monochrome sprite from a run-length encoded string at position (sx, sy) scaled by scale. The sprite uses a single foreground color for filled pixels.

RLE sprite format

CharacterMeaning
#Filled pixel (drawn in color)
.Black pixel — writes palette index 0 (CLR_BLACK), not transparent
$End of row — x resets to sx, y advances by scale
>Skip pixels — advances x by scale without writing any pixel
09Digit prefix — repeat the next command N times (digits accumulate as a decimal number)
[...]Group — repeat the bracketed sub-expression (with optional digit prefix)
!Terminates the sprite string early
A missing count defaults to 1. Digits accumulate as a decimal number before each command.

RLE examples

// "5#3.2#" → 5 filled, 3 black (CLR_BLACK), 2 filled
PrimitiveSprite(1, 10, 10, CLR_WHITE, "5#3.2#", 1);

// 3×3 solid block
PrimitiveSprite(1, 20, 20, CLR_RED, "3#$3#$3#", 1);

// 2× scale 5-pixel horizontal bar
PrimitiveSprite(1, 0, 0, CLR_GREEN, "5#", 2);

// Repeated group: draw "##." four times = "##.##.##.##."
PrimitiveSprite(1, 0, 50, CLR_CYAN, "4[##.]", 1);
Use scale to render pixel-art sprites at integer multiples without pre-scaling your asset. Each logical pixel becomes a scale × scale block.
The . command writes palette index 0 (CLR_BLACK), not a transparent skip. To skip pixels without writing, use >.

ApplyPixelFunc — Per-Pixel Transform

void ApplyPixelFunc(int id, int (*f)(int x, int y, int color));
Iterates every pixel in the image and replaces it with the value returned by f. The callback receives the pixel’s x and y coordinates plus its current palette index, and returns the new palette index. The result is automatically clamped to 0–15 via % 16.
// Invert all colors: flip the nibble within 0–15
int invert(int x, int y, int color) {
    return 15 - color;
}
ApplyPixelFunc(1, invert);
UpdateImage(1);

// Checkerboard overlay
int checker(int x, int y, int color) {
    return ((x + y) % 2 == 0) ? CLR_BLACK : color;
}
ApplyPixelFunc(1, checker);
UpdateImage(1);

Custom Bitmap Font Rendering

Image elements support an optional 8×N bitmap font for drawing text directly into the pixel buffer.
void SetImageFont(int id, unsigned char* font, int h);
void DrawString(int id, int x, int y, const char* txt, int color);
  • SetImageFont — installs a 256-glyph font where each glyph is h bytes tall and 8 bits wide. The buffer is copied internally (256 * h bytes).
  • DrawString — renders txt into the image buffer starting at (x, y). Newlines (\n) advance y by h and reset x. Glyphs are spaced 9px apart.
// Assume `my_font` is a 256*8 byte bitmap font buffer
SetImageFont(1, my_font, 8);
DrawString(1, 5, 5, "Hello\nWorld", CLR_WHITE);
UpdateImage(1);

Immediate Drawing (No Element)

These functions draw directly onto the back-buffer each frame — useful for overlays and HUD elements that do not need to be retained as elements. Because they write to the back-buffer, they must be called from the frame callback (on_every).
void ImmediateText(int x, int y, const char* str, int color);
void ImmediateRect(int x, int y, int w, int h, int fg, int bg);
void ImmediateEllipse(int x, int y, int w, int h, int fg, int bg);
void ImmediateLine(int x1, int y1, int x2, int y2, int color);
ImmediateText adds 11 pixels to y internally before drawing. Passing y=0 renders the text baseline at y=11. Account for this offset when positioning text alongside other immediate draws.
void on_frame(int tick, float dt) {
    // Draw a semi-permanent HUD overlay every frame
    ImmediateRect(5, 5, 120, 20, CLR_WHITE, CLR_BLACK);
    // ImmediateText at y=7 draws baseline at y=18 (7+11)
    ImmediateText(10, 7, "SCORE: 9999", CLR_YELLOW);
    ImmediateLine(0, 30, 640, 30, CLR_LGRAY);
}
Immediate drawing functions produce no retained element. They must be reissued every frame or the output will disappear. For persistent content, use the image element API instead.

Example: Bouncing Ball Animation

This example creates a full-window canvas and animates a bouncing ball using ClearImage, PrimitiveCircle, and UpdateImage each frame.
#include "libLWXGL.h"

#define CANVAS 1
#define W 400
#define H 300
#define RADIUS 15

static float bx = 100, by = 100;
static float vx = 120, vy = 90;  // pixels per second

void on_frame(int tick, float dt) {
    bx += vx * dt;
    by += vy * dt;

    if (bx - RADIUS < 0)     { bx = RADIUS;      vx = -vx; }
    if (bx + RADIUS > W)     { bx = W - RADIUS;  vx = -vx; }
    if (by - RADIUS < 0)     { by = RADIUS;       vy = -vy; }
    if (by + RADIUS > H)     { by = H - RADIUS;   vy = -vy; }

    ClearImage(CANVAS, CLR_BLACK);
    PrimitiveCircle(CANVAS, (int)bx, (int)by, RADIUS, CLR_WHITE, CLR_RED);
    UpdateImage(CANVAS);
}

int main(void) {
    CreateWindow(W, H, "Bouncing Ball", CLR_BLACK, FLAG_NONE);
    CreateImage(CANVAS, 0, 0, W, H);

    MainWindowLoop(60, on_frame);
    TerminateWindow();
    return 0;
}

Build docs developers (and LLMs) love