amiga-bootcamp/08_graphics/rastport.md

13 KiB
Raw Blame History

← Home · Graphics

RastPort — Drawing Primitives and Layers

Overview

RastPort is the primary drawing context in AmigaOS — the equivalent of a "device context" (Windows) or "graphics context" (X11). All graphics primitives (pixel, line, rectangle, polygon, text) operate through a RastPort, which bundles together a target BitMap, drawing pen colors, patterns, font, draw mode, and an optional Layer for clipping.

Every Intuition window and screen has its own RastPort. When you draw into a window, you're drawing through its RastPort.

flowchart TD
    subgraph "RastPort — Drawing Context"
        RP["struct RastPort"]
        RP --> BM["BitMap<br/>(pixel storage)"]
        RP --> PEN["Pens<br/>FgPen, BgPen, AOlPen"]
        RP --> DM["DrawMode<br/>JAM1/JAM2/COMPLEMENT"]
        RP --> FONT["TextFont<br/>(current font)"]
        RP --> PAT["AreaPtrn<br/>(fill pattern)"]
        RP --> LAYER["Layer<br/>(clipping region)"]
        RP --> CP["cp_x, cp_y<br/>(cursor position)"]
    end

    APP["Application Code"] -->|"SetAPen, Move,<br/>Draw, RectFill,<br/>Text, ClipBlit"| RP
    RP -->|"Drawing operations"| BM
    LAYER -->|"Clips to visible region"| BM

    style RP fill:#e8f4fd,stroke:#2196f3,color:#333
    style BM fill:#c8e6c9,stroke:#2e7d32,color:#333
    style LAYER fill:#fff9c4,stroke:#f9a825,color:#333

struct RastPort

/* graphics/rastport.h — NDK39 */
struct RastPort {
    struct Layer   *Layer;       /* associated layer (NULL = no clipping) */
    struct BitMap  *BitMap;      /* target bitmap */
    UWORD          *AreaPtrn;   /* area fill pattern */
    struct TmpRas  *TmpRas;     /* temp raster for area fills/floods */
    struct AreaInfo *AreaInfo;   /* area fill vertex buffer */
    struct GelsInfo *GelsInfo;   /* GEL (BOB/VSprite) list */
    UBYTE           Mask;        /* plane mask (which planes to draw to) */
    BYTE            FgPen;       /* foreground pen color index */
    BYTE            BgPen;       /* background pen color index */
    BYTE            AOlPen;      /* area outline pen */
    BYTE            DrawMode;    /* JAM1, JAM2, COMPLEMENT, INVERSVID */
    BYTE            AreaPtSz;    /* area pattern size (log2) */
    BYTE            linpatcnt;   /* line pattern counter */
    BYTE            dummy;
    UWORD           Flags;       /* FRST_DOT etc. */
    UWORD           LinePtrn;    /* 16-bit line dash pattern */
    WORD            cp_x, cp_y;  /* current pen position */
    UWORD           minterms[8];
    WORD            PenWidth;
    WORD            PenHeight;
    struct TextFont *Font;       /* current text font */
    UBYTE           AlgoStyle;   /* algorithmic style flags */
    UBYTE           TxFlags;
    UWORD           TxHeight;
    UWORD           TxWidth;
    UWORD           TxBaseline;
    WORD            TxSpacing;
    APTR           *RP_User;
    /* ... */
};

Draw Modes

The draw mode controls how new pixels combine with existing content:

flowchart LR
    subgraph "JAM1 — Transparent"
        J1BG["Background<br/>unchanged"] --- J1FG["Foreground<br/>drawn with FgPen"]
    end

    subgraph "JAM2 — Opaque"
        J2BG["Background<br/>drawn with BgPen"] --- J2FG["Foreground<br/>drawn with FgPen"]
    end

    subgraph "COMPLEMENT — XOR"
        XBG["All pixels<br/>XOR with existing"]
    end
#define JAM1        0   /* draw FgPen only; background pixels are NOT touched */
#define JAM2        1   /* draw FgPen AND BgPen — fully opaque */
#define COMPLEMENT  2   /* XOR all drawn pixels with existing content */
#define INVERSVID   4   /* swap foreground/background (for text inverse) */
Mode Text Example Fill Example Use Case
JAM1 Characters drawn, background shows through Solid fill with FgPen Transparent overlays, labels on images
JAM2 Characters + background box drawn Same as JAM1 for fills Opaque text on busy backgrounds
COMPLEMENT XOR of text pixels with screen XOR fill Rubber-band selection, dragging cursors
`JAM1 INVERSVID` Background drawn with FgPen, chars transparent

Drawing Primitives

Pen and Position Setup

/* Set pen colors: */
SetAPen(rp, 1);       /* foreground = color register 1 */
SetBPen(rp, 0);       /* background = color register 0 */
SetDrMd(rp, JAM1);    /* transparent background mode */

/* OS 3.0+ — use named pen for correct Workbench colors: */
SetAPen(rp, screen->RastPort.BitMap->Depth > 1 ?
    ObtainBestPen(screen->ViewPort.ColorMap,
                  0xFF000000, 0x00000000, 0x00000000,  /* red */
                  OBP_Precision, PRECISION_GUI,
                  TAG_DONE) : 1);

Lines and Pixels

flowchart LR
    M["Move(rp, 10, 20)"] -->|"sets cp_x, cp_y"| D1["Draw(rp, 100, 20)"]
    D1 -->|"draws line,<br/>updates cp"| D2["Draw(rp, 100, 80)"]
    D2 -->|"draws line,<br/>updates cp"| D3["Draw(rp, 10, 80)"]
    D3 -->|"draws line,<br/>updates cp"| D4["Draw(rp, 10, 20)"]

    style M fill:#e8f4fd,stroke:#2196f3,color:#333
/* Move cursor (no drawing): */
Move(rp, 100, 50);

/* Draw line from current position to (x,y), update cp: */
Draw(rp, 200, 100);
/* cp is now (200, 100) — next Draw continues from here */

/* Draw a connected polygon: */
Move(rp, 10, 10);
Draw(rp, 100, 10);    /* top edge */
Draw(rp, 100, 80);    /* right edge */
Draw(rp, 10, 80);     /* bottom edge */
Draw(rp, 10, 10);     /* close: left edge */

/* Single pixel: */
WritePixel(rp, 160, 120);
LONG color = ReadPixel(rp, 160, 120);

/* Dashed lines: */
SetDrPt(rp, 0xF0F0);  /* 16-bit pattern: 1111000011110000 */
Draw(rp, 200, 100);    /* draws dashed line */
SetDrPt(rp, 0xFFFF);  /* restore solid */

Rectangles and Fills

/* Solid filled rectangle (uses FgPen + DrawMode): */
SetAPen(rp, 3);
RectFill(rp, 10, 10, 100, 50);  /* x1,y1 to x2,y2 inclusive */

/* Erase to background (clear a region): */
SetAPen(rp, 0);
SetDrMd(rp, JAM1);
RectFill(rp, 0, 0, 319, 255);

/* Scroll a region (with clear): */
ScrollRaster(rp, dx, dy, x1, y1, x2, y2);
/* Shifts content by (dx,dy); exposed area cleared to BgPen */

Text Rendering

flowchart LR
    ATTR["TextAttr<br/>(name, size)"] -->|"OpenFont /<br/>OpenDiskFont"| TF["TextFont"]
    TF -->|"SetFont(rp, font)"| RP["RastPort"]
    RP -->|"Move + Text"| OUT["Rendered text<br/>on bitmap"]
/* Set font: */
struct TextAttr ta = {"topaz.font", 8, 0, FPF_ROMFONT};
struct TextFont *font = OpenFont(&ta);
SetFont(rp, font);

/* Render text at position: */
Move(rp, 20, 30);          /* baseline position */
Text(rp, "Hello Amiga", 11);

/* Measure text width before rendering (for alignment): */
UWORD width = TextLength(rp, "Hello Amiga", 11);
/* Right-align: */
Move(rp, screenWidth - width - 10, 30);
Text(rp, "Hello Amiga", 11);

/* Bold/italic (algorithmic): */
UWORD supported = AskSoftStyle(rp);
SetSoftStyle(rp, FSF_BOLD | FSF_ITALIC, supported);
Text(rp, "Bold Italic", 11);
SetSoftStyle(rp, 0, supported);  /* restore */

Area Fills (Polygons)

/* Area fills require setup: TmpRas + AreaInfo */
UBYTE areaBuffer[5 * 5];  /* 5 vertices × 5 bytes each */
struct AreaInfo areaInfo;
InitArea(&areaInfo, areaBuffer, 5);
rp->AreaInfo = &areaInfo;

PLANEPTR tmpRasData = AllocRaster(320, 256);
struct TmpRas tmpRas;
InitTmpRas(&tmpRas, tmpRasData, RASSIZE(320, 256));
rp->TmpRas = &tmpRas;

/* Draw a filled triangle: */
AreaMove(rp, 100, 10);     /* first vertex */
AreaDraw(rp, 200, 180);    /* second vertex */
AreaDraw(rp, 20, 180);     /* third vertex */
AreaEnd(rp);               /* fill and close */

/* Cleanup: */
FreeRaster(tmpRasData, 320, 256);

Flood Fill

/* Flood fill from a seed point: */
/* Requires TmpRas (same setup as area fills) */
Flood(rp, 1, 50, 50);
/* mode 1 = fill until FgPen color boundary */
/* mode 0 = fill all connected pixels of same color as seed */

Blitting (Block Transfer)

flowchart LR
    SRC["Source RastPort<br/>(or BitMap)"] -->|"ClipBlit /<br/>BltBitMapRastPort"| DST["Destination RastPort"]
    
    subgraph "Minterm Controls"
        MT["0xC0 = copy<br/>0x30 = invert copy<br/>0x50 = XOR<br/>0x00 = clear"]
    end
    MT --> DST
/* Copy region between RastPorts (respects clipping): */
ClipBlit(srcRP, sx, sy,     /* source position */
         dstRP, dx, dy,     /* destination position */
         width, height,
         0xC0);             /* minterm: straight copy */

/* Copy from BitMap to RastPort: */
BltBitMapRastPort(srcBM, sx, sy,
                  dstRP, dx, dy,
                  width, height,
                  0xC0);

/* Common minterms: */
/* 0xC0 = A (copy source)           */
/* 0x30 = NOT A (invert source)     */
/* 0x50 = A XOR B (toggle)          */
/* 0x00 = clear destination         */
/* 0xFF = set all bits               */

Layers — Window Clipping

When rp->Layer != NULL, all drawing is automatically clipped to the layer's visible region. Intuition creates layers for every window — this is how overlapping windows work without drawing over each other.

flowchart TD
    subgraph "Screen"
        subgraph "Window A (front)"
            LA["Layer A<br/>(fully visible)"]
        end
        subgraph "Window B (behind)"
            LB["Layer B<br/>(partially obscured)"]
        end
        subgraph "Window C (behind both)"
            LC["Layer C<br/>(mostly obscured)"]
        end
    end

    DRAW["Draw(windowB->RPort, ...)"] --> LB
    LB -->|"ClipRects exclude<br/>obscured regions"| BM["BitMap<br/>(only visible<br/>portions drawn)"]

    style LA fill:#c8e6c9,stroke:#2e7d32,color:#333
    style LB fill:#fff9c4,stroke:#f9a825,color:#333
    style LC fill:#ffcdd2,stroke:#c62828,color:#333

Each layer maintains a list of ClipRects — rectangles defining which parts of the layer are visible. When you draw to a partially obscured window, layers.library breaks your drawing operation into multiple clipped sub-draws, one per visible ClipRect.

/* Direct layer creation (Intuition does this for windows): */
struct Layer_Info *li = NewLayerInfo();
struct Layer *layer = CreateUpfrontLayer(li, bm,
    x1, y1, x2, y2,
    LAYERSIMPLE,  /* or LAYERSMART, LAYERSUPER */
    NULL);
struct RastPort *rp = layer->rp;  /* use this for drawing */

/* LAYERSIMPLE  — no backing store; app must redraw damaged areas */
/* LAYERSMART   — automatic backing store; OS handles redraw */
/* LAYERSUPER   — super bitmap; full offscreen buffer */

/* Layer clipping is automatic — Draw, RectFill, Text all respect it */
Draw(rp, 200, 100);  /* clipped to visible portion of layer */

/* Cleanup: */
DeleteLayer(0, layer);
DisposeLayerInfo(li);

Layer Types

Type Flag Backing Store Damage Handling Memory
Simple LAYERSIMPLE None App receives IDCMP_REFRESHWINDOW and must redraw Minimal
Smart LAYERSMART Auto-saved obscured regions OS restores automatically Moderate
Super LAYERSUPER Full off-screen bitmap Full bitmap always valid High

Tip

WFLG_SIMPLE_REFRESH windows use the least memory but require the most application code (you must handle IDCMP_REFRESHWINDOW). WFLG_SMART_REFRESH is the default for most applications — Intuition saves/restores obscured regions automatically.


Patterns

Line Patterns

/* 16-bit repeating pattern for dashed lines: */
SetDrPt(rp, 0xFF00);   /* ████████░░░░░░░░ — long dash */
SetDrPt(rp, 0xF0F0);   /* ████░░░░████░░░░ — medium dash */
SetDrPt(rp, 0xAAAA);   /* █░█░█░█░█░█░█░█░ — dotted */
SetDrPt(rp, 0xFCFC);   /* ██████░░██████░░ — dash-dot */

Area Fill Patterns

/* Area patterns are powers-of-2 height, 16 bits wide: */
UWORD checkerPattern[] = { 0x5555, 0xAAAA };  /* 2-line checkerboard */
rp->AreaPtrn = checkerPattern;
rp->AreaPtSz = 1;    /* log2(2) = 1 */

/* Now RectFill uses the pattern instead of solid fill: */
RectFill(rp, 10, 10, 100, 80);

/* Multiplane patterns (one set per bitplane): */
UWORD brickPattern[] = {
    /* plane 0: */  0xFFFF, 0x8080, 0xFFFF, 0x0808,
    /* plane 1: */  0xFFFF, 0x8080, 0xFFFF, 0x0808
};
rp->AreaPtrn = brickPattern;
rp->AreaPtSz = 2;   /* log2(4 lines) = 2 */
rp->Mask |= 0x02;   /* enable plane 1 pattern */

Plane Mask — Selective Bitplane Drawing

/* Mask controls which bitplanes are affected by drawing: */
rp->Mask = 0xFF;  /* all planes — default */
rp->Mask = 0x01;  /* only plane 0 — fast for single-plane effects */
rp->Mask = 0x03;  /* planes 0 and 1 only */

/* Use case: draw a 2-color overlay without disturbing other planes: */
rp->Mask = 0x04;  /* only plane 2 */
SetAPen(rp, 4);   /* color index with bit 2 set */
RectFill(rp, 0, 0, 319, 255);
rp->Mask = 0xFF;  /* restore */

References

  • NDK39: graphics/rastport.h, graphics/gfxmacros.h
  • ADCD 2.1: SetAPen, Move, Draw, Text, RectFill, ClipBlit
  • See also: bitmap.md — BitMap structure and allocation
  • See also: layers.md — layers.library detailed reference
  • See also: text_fonts.md — font loading and rendering
  • See also: blitter.md — hardware Blitter used by BltBitMap