Modern QB64 Graphics

Store colors in _UNSIGNED LONG variables: DIM sky AS _UNSIGNED LONG: sky = _RGB32(135, 206, 235).

23.1 32-bit screens and colors

_NEWIMAGE(w, h, mode) create an image (mode 32 = 32-bit, 256 = 8-bit, or a legacy SCREEN number)

_RGB32(r, g, b) / _RGBA32(r, g, b, a) 32-bit color values (_UNSIGNED LONG) _RGB(r, g, b) / _RGBA closest color for the current destination (works in palette modes)

_RED32(c), _GREEN32(c), _BLUE32(c), _ALPHA32(c) _WIDTH(img), _HEIGHT(img) image size (current destination if omitted) _PRINTSTRING (x, y), text$ text at pixel coordinates _FULLSCREEN / _FULLSCREEN _OFF toggle full screen $RESIZE:ON / $RESIZE:STRETCH allow window resizing

Store colors in _UNSIGNED LONG variables: DIM sky AS _UNSIGNED LONG: sky = _RGB32(135, 206, 235).

SCREEN _NEWIMAGE(800, 600, 32)       ' 800x600 window, 32-bit color
_TITLE "QB64-PE Graphics"
_SCREENMOVE _MIDDLE                  ' center the window on the desktop

CLS , _RGB32(20, 24, 40)             ' clear to a dark blue
LINE (100, 100)-(300, 250), _RGB32(255, 80, 80), BF
CIRCLE (500, 200), 80, _RGB32(80, 255, 120)
PAINT (500, 200), _RGB32(80, 255, 120), _RGB32(80, 255, 120)
LINE (200, 200)-(600, 450), _RGBA32(80, 160, 255, 128), BF   ' 50% transparent
COLOR _RGB32(255, 255, 255), _RGB32(0, 0, 0)
_PRINTSTRING (20, 560), "Width:" + STR$(_WIDTH) + "  Height:" + STR$(_HEIGHT)
SLEEP

23.2 Double buffering with _DISPLAY and _LIMIT

Drawing directly to the visible screen causes flicker. Call _DISPLAY once per frame: after the first call, QB64 only shows the screen when you call _DISPLAY again (_AUTODISPLAY restores automatic updates).

_LIMIT fps sleeps just enough to cap the loop rate — essential to avoid using 100% of a CPU core.

SCREEN _NEWIMAGE(640, 480, 32)
DIM x AS SINGLE, y AS SINGLE, dx AS SINGLE, dy AS SINGLE
x = 320: y = 240: dx = 3.5: dy = 2.25
DO
    CLS                                     ' clear the back buffer
    x = x + dx: y = y + dy
    IF x < 15 OR x > 625 THEN dx = -dx
    IF y < 15 OR y > 465 THEN dy = -dy
    CIRCLE (x, y), 15, _RGB32(255, 200, 0)
    PAINT (x, y), _RGB32(255, 200, 0), _RGB32(255, 200, 0)
    _PRINTSTRING (10, 10), "Press Esc to quit"
    _DISPLAY                                ' show the finished frame
    _LIMIT 60                               ' at most 60 iterations per second
LOOP UNTIL _KEYDOWN(27)

23.3 Images: loading, drawing, freeing

Image handles are negative LONG values. Always _FREEIMAGE images you create in loops — otherwise memory leaks.

SCREEN _NEWIMAGE(800, 600, 32)
DIM img AS LONG
img = _LOADIMAGE("assets/ship.png", 32)     ' PNG, JPG, BMP, GIF, TGA, and more
IF img >= -1 THEN PRINT "Could not load image": END   ' valid handles are < -1

_PUTIMAGE (100, 100), img                              ' draw at original size
_PUTIMAGE (300, 100)-(427, 227), img                   ' draw scaled into a rectangle
_PUTIMAGE (500, 100)-STEP(63, 63), img                 ' 64x64 with STEP
_PUTIMAGE (700, 100)-(636, 164), img                   ' reversed x: mirrored horizontally
PRINT "Image size:"; _WIDTH(img); "x"; _HEIGHT(img)
_FREEIMAGE img                                         ' release memory when done
SLEEP

23.4 Drawing into off-screen images: _DEST and _SOURCE

_SOURCE sets which image POINT and GET read from. _COPYIMAGE(img) duplicates an image. _SETALPHA changes alpha values in a range of colors.

SCREEN _NEWIMAGE(640, 480, 32)
DIM sprite AS LONG
sprite = _NEWIMAGE(32, 32, 32)
_DEST sprite                                 ' all drawing now goes to the sprite
CLS , _RGB32(255, 0, 255)                    ' magenta background (will be transparent)
CIRCLE (16, 16), 14, _RGB32(0, 200, 255)
PAINT (16, 16), _RGB32(0, 200, 255), _RGB32(0, 200, 255)
LINE (10, 10)-(13, 13), _RGB32(255, 255, 255), BF
_DEST 0                                      ' 0 = the screen
_CLEARCOLOR _RGB32(255, 0, 255), sprite      ' make magenta transparent

FOR i = 1 TO 50
    _PUTIMAGE (RND * 600, RND * 440), sprite
NEXT
SLEEP

23.5 Sprite sheets and animation

A sprite sheet holds all animation frames in one image. Copy one frame with the source-rectangle form of _PUTIMAGE:

' _PUTIMAGE (dx1, dy1)-(dx2, dy2), source, destination, (sx1, sy1)-(sx2, sy2)
SCREEN _NEWIMAGE(640, 480, 32)
CONST FRAME_W = 32, FRAME_H = 32, FRAMES = 4
DIM sheet AS LONG
sheet = _NEWIMAGE(FRAME_W * FRAMES, FRAME_H, 32)   ' build a demo sheet procedurally
_DEST sheet
FOR f = 0 TO FRAMES - 1
    CIRCLE (f * FRAME_W + 16, 16), 4 + f * 3, _RGB32(255, 120 + f * 40, 0)
NEXT
_DEST 0

DIM frame AS INTEGER, t AS DOUBLE
t = TIMER
DO
    CLS
    IF TIMER - t > 0.15 THEN frame = (frame + 1) MOD FRAMES: t = TIMER
    sx = frame * FRAME_W
    _PUTIMAGE (304, 224)-STEP(63, 63), sheet, 0, (sx, 0)-(sx + FRAME_W - 1, FRAME_H - 1)
    _DISPLAY
    _LIMIT 60
LOOP UNTIL INKEY$ <> ""
_FREEIMAGE sheet

23.6 Fonts and text

Built-in fonts 8 and 16 (_FONT 8, _FONT 16) are always available. Free fonts with _FREEFONT after switching away from them.

SCREEN _NEWIMAGE(800, 300, 32)
DIM f AS LONG
f = _LOADFONT("arial.ttf", 36)        ' TrueType font file; path may need adjusting per OS
IF f > 0 THEN _FONT f
_PRINTMODE _KEEPBACKGROUND            ' transparent text background
COLOR _RGB32(255, 220, 0)
_PRINTSTRING (40, 100), "Hello, fonts!"
PRINT "Text width in pixels:"; _PRINTWIDTH("Hello, fonts!")
SLEEP

23.7 Hardware images and other features

_COPYIMAGE(img, 33) creates a hardware image drawn by the GPU — very fast for many sprites (_DISPLAYORDER controls layering).

_MAPTRIANGLE maps a triangle of one image onto another (2-D texture mapping and simple 3-D).

_SCREENIMAGE captures the desktop; recent QB64-PE versions can save images to files with _SAVEIMAGE (check the wiki for your version).

_ICON img sets the window icon.

FreeBASIC: ScreenRes 800, 600, 32, RGB(r, g, b), RGBA, ImageCreate(w, h), BLoad "file.bmp", img (BMP natively; PNG via libraries), Put (x, y), img, Trans (transparent magenta), ImageDestroy, ScreenLock/ScreenUnlock or Flip for page flipping, Draw String (x, y), text. Libraries: fbgfx (built in), SDL2, raylib, OpenGL bindings. VB.NET: Bitmap, Graphics.DrawImage, double buffering via Me.DoubleBuffered = True; for games, MonoGame (C# mostly, but usable from VB).