mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
docs(amiga): complete AmigaOS 3.1/3.2 developer reference — 172 files across 17 sections
Comprehensive technical documentation covering: - Hardware: OCS/ECS/AGA custom chip registers, Copper & Blitter deep dives - Boot sequence: cold boot through startup-sequence - Binary format: HUNK executable spec, relocation, debug info - Linking & ABI: .fd files, LVO tables, register calling conventions - Exec kernel: tasks, interrupts, memory, signals, semaphores - AmigaDOS: file I/O, FFS/OFS layout, CLI/Shell scripting - Graphics: planar bitmaps, Copper programming, HAM/EHB modes - Intuition: screens, windows, IDCMP, BOOPSI - Devices: trackdisk, SCSI, serial, timer, audio, keyboard - Libraries: utility, expansion, IFFParse, locale, ARexx - Networking: bsdsocket API, SANA-II, TCP/IP stack comparison - Toolchain: GCC, vasm/vlink, SAS/C, NDK, debugging - Reverse engineering: IDA/Ghidra setup, compiler fingerprints, case studies - CPU & MMU: 68040/060 emulation libs, PMMU, cache management - Driver development: SANA-II, Picasso96/RTG, AHI audio All files include breadcrumb navigation. No local paths or proprietary content.
This commit is contained in:
parent
f07a368bf1
commit
21751c0025
172 changed files with 19701 additions and 0 deletions
21
08_graphics/README.md
Normal file
21
08_graphics/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[← Home](../README.md)
|
||||
|
||||
# Graphics Subsystem — Overview
|
||||
|
||||
## Section Index
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| [gfx_base.md](gfx_base.md) | GfxBase structure and global graphics state |
|
||||
| [bitmap.md](bitmap.md) | BitMap structure, planar layout, allocation |
|
||||
| [copper.md](copper.md) | Copper coprocessor, instruction format, UCopList |
|
||||
| [blitter.md](blitter.md) | Blitter DMA engine, minterms, BltBitMap |
|
||||
| [sprites.md](sprites.md) | Hardware sprites, SimpleSprite, MoveSprite |
|
||||
| [rastport.md](rastport.md) | RastPort, drawing primitives, layers |
|
||||
| [views.md](views.md) | View, ViewPort, MakeVPort, display construction |
|
||||
| [text_fonts.md](text_fonts.md) | TextFont, TextAttr, OpenFont, Text rendering |
|
||||
| [display_modes.md](display_modes.md) | Display database, ModeID, monitor specs |
|
||||
| [ham_ehb_modes.md](ham_ehb_modes.md) | HAM6, HAM8, and EHB special display modes |
|
||||
| [animation.md](animation.md) | AnimOb, BOB, VSprite, GEL system |
|
||||
| [copper_programming.md](copper_programming.md) | Copper deep dive: architecture, examples, system API |
|
||||
| [blitter_programming.md](blitter_programming.md) | Blitter deep dive: minterms, cookie-cut, line draw |
|
||||
110
08_graphics/animation.md
Normal file
110
08_graphics/animation.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Animation — GEL System: BOBs, VSprites, AnimObs
|
||||
|
||||
## Overview
|
||||
|
||||
The **GEL (Graphics ELement)** system provides high-level animated sprite and bitmap overlay support. It manages VSprites (virtual sprites that can use hardware or software rendering), BOBs (Blitter OBjects — arbitrary-sized bitmaps overlaid on a playfield), and AnimObs (animation objects with sequencing).
|
||||
|
||||
---
|
||||
|
||||
## VSprite
|
||||
|
||||
```c
|
||||
/* graphics/gels.h — NDK39 */
|
||||
struct VSprite {
|
||||
struct VSprite *NextVSprite;
|
||||
struct VSprite *PrevVSprite;
|
||||
struct VSprite *DrawPath;
|
||||
struct VSprite *ClearPath;
|
||||
WORD OldY, OldX; /* previous position */
|
||||
WORD Flags; /* VSPRITE, SAVEBACK, OVERLAY, MUSTDRAW */
|
||||
WORD Y, X; /* current position */
|
||||
WORD Height;
|
||||
WORD Width; /* width in words */
|
||||
WORD Depth;
|
||||
WORD MeMask; /* collision mask */
|
||||
WORD HitMask;
|
||||
WORD *ImageData; /* sprite image */
|
||||
WORD *BorderLine; /* collision border */
|
||||
WORD *CollMask; /* collision mask data */
|
||||
WORD *SprColors; /* colour table */
|
||||
struct Bob *VSBob; /* if this VSprite backs a BOB */
|
||||
BYTE PlanePick;
|
||||
BYTE PlaneOnOff;
|
||||
/* ... */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BOB (Blitter Object)
|
||||
|
||||
```c
|
||||
struct Bob {
|
||||
WORD Flags;
|
||||
WORD *SaveBuffer; /* background save buffer */
|
||||
WORD *ImageShadow; /* shadow mask for cookie-cut */
|
||||
struct Bob *Before;
|
||||
struct Bob *After;
|
||||
struct VSprite *BobVSprite; /* associated VSprite */
|
||||
struct AnimComp *BobComp; /* if part of animation */
|
||||
struct DBufPacket *DBuffer; /* double-buffer packet */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Pattern
|
||||
|
||||
```c
|
||||
struct GelsInfo gi;
|
||||
struct VSprite headVS, tailVS;
|
||||
|
||||
/* Initialise GEL system: */
|
||||
InitGels(&headVS, &tailVS, &gi);
|
||||
rp->GelsInfo = &gi;
|
||||
|
||||
/* Add a VSprite/BOB: */
|
||||
AddVSprite(&myVSprite, rp);
|
||||
/* or */
|
||||
AddBob(&myBob, rp);
|
||||
|
||||
/* Each frame: */
|
||||
SortGList(rp); /* sort by Y position */
|
||||
DrawGList(rp, &vp); /* render all GELs */
|
||||
WaitTOF(); /* sync to vertical blank */
|
||||
|
||||
/* Cleanup: */
|
||||
RemVSprite(&myVSprite);
|
||||
/* or */
|
||||
RemBob(&myBob);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AnimOb — Animation Sequences
|
||||
|
||||
```c
|
||||
struct AnimOb {
|
||||
struct AnimOb *NextOb;
|
||||
struct AnimOb *PrevOb;
|
||||
LONG Clock; /* frame counter */
|
||||
WORD AnOldY, AnOldX;
|
||||
WORD AnY, AnX; /* current position */
|
||||
WORD YVel, XVel; /* velocity */
|
||||
WORD YAccel, XAccel; /* acceleration */
|
||||
WORD RingYTrans; /* ring buffer Y translation */
|
||||
WORD RingXTrans;
|
||||
struct AnimComp *HeadComp; /* component chain */
|
||||
/* ... */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/gels.h`, `graphics/gelsinternal.h`
|
||||
- ADCD 2.1: `InitGels`, `AddVSprite`, `AddBob`, `SortGList`, `DrawGList`
|
||||
- *Amiga ROM Kernel Reference Manual: Libraries* — GELs chapter
|
||||
117
08_graphics/bitmap.md
Normal file
117
08_graphics/bitmap.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# BitMap — Planar Bitmap Structure and Layout
|
||||
|
||||
## Overview
|
||||
|
||||
Amiga display memory uses **planar** layout: each bitplane is a separate contiguous memory region. A pixel's colour index is formed by reading one bit from each plane at the same x,y position. This is fundamentally different from chunky (packed-pixel) or interleaved formats.
|
||||
|
||||
---
|
||||
|
||||
## struct BitMap
|
||||
|
||||
```c
|
||||
/* graphics/gfx.h — NDK39 */
|
||||
struct BitMap {
|
||||
UWORD BytesPerRow; /* bytes per row per plane (must be even) */
|
||||
UWORD Rows; /* height in pixels */
|
||||
UBYTE Flags; /* BMF_* flags */
|
||||
UBYTE Depth; /* number of bitplanes (1–8) */
|
||||
UWORD pad;
|
||||
PLANEPTR Planes[8]; /* pointers to each bitplane buffer */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BMF_ Flags
|
||||
|
||||
```c
|
||||
#define BMF_CLEAR (1<<0) /* clear planes on allocation */
|
||||
#define BMF_DISPLAYABLE (1<<1) /* allocated in displayable (Chip) RAM */
|
||||
#define BMF_INTERLEAVED (1<<2) /* planes are interleaved in memory */
|
||||
#define BMF_STANDARD (1<<3) /* use standard allocation */
|
||||
#define BMF_MINPLANES (1<<4) /* minimum number of planes */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Planar Memory Layout
|
||||
|
||||
For a 320×256×4 display (16 colours):
|
||||
|
||||
```
|
||||
BytesPerRow = 320/8 = 40 bytes
|
||||
Rows = 256
|
||||
Depth = 4
|
||||
|
||||
Plane 0: 40 × 256 = 10,240 bytes (bit 0 of colour index)
|
||||
Plane 1: 40 × 256 = 10,240 bytes (bit 1)
|
||||
Plane 2: 40 × 256 = 10,240 bytes (bit 2)
|
||||
Plane 3: 40 × 256 = 10,240 bytes (bit 3)
|
||||
|
||||
Total = 4 × 10,240 = 40,960 bytes
|
||||
```
|
||||
|
||||
Pixel colour at (x, y):
|
||||
```
|
||||
bit0 = (Planes[0][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
|
||||
bit1 = (Planes[1][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
|
||||
bit2 = (Planes[2][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
|
||||
bit3 = (Planes[3][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
|
||||
colour_index = (bit3 << 3) | (bit2 << 2) | (bit1 << 1) | bit0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Allocation
|
||||
|
||||
```c
|
||||
/* OS 3.0+ — AllocBitMap: */
|
||||
struct BitMap *bm = AllocBitMap(320, 256, 4,
|
||||
BMF_CLEAR | BMF_DISPLAYABLE, NULL);
|
||||
/* Always in Chip RAM when BMF_DISPLAYABLE */
|
||||
|
||||
/* Manual allocation (OS 1.x compatible): */
|
||||
struct BitMap bm;
|
||||
InitBitMap(&bm, 4, 320, 256);
|
||||
for (int i = 0; i < 4; i++)
|
||||
bm.Planes[i] = AllocRaster(320, 256); /* MEMF_CHIP */
|
||||
|
||||
/* Free: */
|
||||
FreeBitMap(bm); /* or FreeRaster per plane */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interleaved BitMaps
|
||||
|
||||
With `BMF_INTERLEAVED`, all planes are stored sequentially row by row:
|
||||
```
|
||||
Row 0, Plane 0: 40 bytes
|
||||
Row 0, Plane 1: 40 bytes
|
||||
Row 0, Plane 2: 40 bytes
|
||||
Row 0, Plane 3: 40 bytes
|
||||
Row 1, Plane 0: 40 bytes
|
||||
...
|
||||
```
|
||||
|
||||
BytesPerRow becomes `40 × Depth = 160`, and each `Planes[i]` pointer is offset by `i * 40` from the base. This layout is more cache-friendly and allows single-pass blits.
|
||||
|
||||
---
|
||||
|
||||
## AGA 8-Bit Bitmaps
|
||||
|
||||
AGA (A1200/A4000) supports up to 8 bitplanes = 256 colours:
|
||||
```c
|
||||
struct BitMap *bm = AllocBitMap(320, 256, 8, BMF_CLEAR | BMF_DISPLAYABLE, NULL);
|
||||
/* 8 planes × 10,240 = 81,920 bytes of Chip RAM */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/gfx.h`
|
||||
- ADCD 2.1: `AllocBitMap`, `FreeBitMap`, `InitBitMap`
|
||||
- HRM: *Amiga Hardware Reference Manual* — bitplane DMA chapter
|
||||
109
08_graphics/blitter.md
Normal file
109
08_graphics/blitter.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Blitter — DMA Engine, Minterms, BltBitMap
|
||||
|
||||
## Overview
|
||||
|
||||
The **Blitter** is a DMA engine in the custom chips that performs bulk memory operations: block copies, line drawing, area fills, and arbitrary boolean combinations of up to three source bitmaps. It operates independently of the CPU, freeing the 68k for other work.
|
||||
|
||||
---
|
||||
|
||||
## Channels
|
||||
|
||||
The blitter has four DMA channels:
|
||||
|
||||
| Channel | Name | Direction | Description |
|
||||
|---|---|---|---|
|
||||
| A | Source A | Read | First source bitmap |
|
||||
| B | Source B | Read | Second source (often mask/pattern) |
|
||||
| C | Source C | Read | Third source (typically destination for read-modify-write) |
|
||||
| D | Destination | Write | Output |
|
||||
|
||||
Each channel has: pointer register, modulo register, shift register (A/B only), and first/last word masks (A only).
|
||||
|
||||
---
|
||||
|
||||
## Minterm Logic
|
||||
|
||||
The blitter combines A, B, C inputs using an 8-bit **minterm** value. Each bit selects whether the output is 1 for a specific combination:
|
||||
|
||||
| Bit | A | B | C | Common Use |
|
||||
|---|---|---|---|---|
|
||||
| 7 | 1 | 1 | 1 | — |
|
||||
| 6 | 1 | 1 | 0 | — |
|
||||
| 5 | 1 | 0 | 1 | — |
|
||||
| 4 | 1 | 0 | 0 | — |
|
||||
| 3 | 0 | 1 | 1 | — |
|
||||
| 2 | 0 | 1 | 0 | — |
|
||||
| 1 | 0 | 0 | 1 | — |
|
||||
| 0 | 0 | 0 | 0 | — |
|
||||
|
||||
Common minterm values:
|
||||
|
||||
| Minterm | Hex | Operation |
|
||||
|---|---|---|
|
||||
| `$F0` | `A` | Copy A to D (straight copy) |
|
||||
| `$CA` | `AB + ~AC` | Cookie-cut: A=mask, B=source, C=background |
|
||||
| `$3C` | `A XOR C` | XOR blit (sprite toggle) |
|
||||
| `$0F` | `NOT A` | Invert source |
|
||||
| `$00` | `0` | Clear destination |
|
||||
| `$FF` | `1` | Fill destination with 1s |
|
||||
|
||||
---
|
||||
|
||||
## Register Map
|
||||
|
||||
| Address | Name | Description |
|
||||
|---|---|---|
|
||||
| `$DFF040` | `BLTCON0` | Control: use-channels + minterm + shift-A |
|
||||
| `$DFF042` | `BLTCON1` | Control: direction, fill mode, line mode |
|
||||
| `$DFF044` | `BLTAFWM` | First word mask for channel A |
|
||||
| `$DFF046` | `BLTALWM` | Last word mask for channel A |
|
||||
| `$DFF048` | `BLTCPT` | Channel C pointer (high word) |
|
||||
| `$DFF04A` | `BLTCPT` | Channel C pointer (low word) |
|
||||
| `$DFF04C` | `BLTBPT` | Channel B pointer |
|
||||
| `$DFF050` | `BLTAPT` | Channel A pointer |
|
||||
| `$DFF054` | `BLTDPT` | Channel D pointer (destination) |
|
||||
| `$DFF058` | `BLTSIZE` | Size and start: `(height << 6) | width_words` |
|
||||
| `$DFF064` | `BLTCMOD` | Channel C modulo |
|
||||
| `$DFF062` | `BLTBMOD` | Channel B modulo |
|
||||
| `$DFF060` | `BLTAMOD` | Channel A modulo |
|
||||
| `$DFF066` | `BLTDMOD` | Channel D modulo |
|
||||
|
||||
---
|
||||
|
||||
## OS-Level Blitter Functions
|
||||
|
||||
```c
|
||||
/* graphics.library */
|
||||
|
||||
/* Copy rectangular region between bitmaps: */
|
||||
LONG BltBitMap(
|
||||
struct BitMap *srcBM, WORD srcX, WORD srcY,
|
||||
struct BitMap *dstBM, WORD dstX, WORD dstY,
|
||||
WORD sizeX, WORD sizeY,
|
||||
UBYTE minterm, /* usually $C0 = copy */
|
||||
UBYTE mask, /* plane mask */
|
||||
APTR tempA /* temp buffer or NULL */
|
||||
);
|
||||
|
||||
/* Blit into RastPort (clips to layer): */
|
||||
void BltBitMapRastPort(struct BitMap *src, WORD srcX, WORD srcY,
|
||||
struct RastPort *rp, WORD dstX, WORD dstY,
|
||||
WORD sizeX, WORD sizeY, UBYTE minterm);
|
||||
|
||||
/* Wait for blitter completion: */
|
||||
void WaitBlit(void); /* must call before freeing blit buffers */
|
||||
|
||||
/* Gain exclusive blitter access: */
|
||||
void OwnBlitter(void);
|
||||
void DisownBlitter(void);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Amiga Hardware Reference Manual* — Blitter chapter
|
||||
- NDK39: `hardware/blit.h`, `graphics/gfx.h`
|
||||
- ADCD 2.1: `BltBitMap`, `BltBitMapRastPort`, `OwnBlitter`
|
||||
257
08_graphics/blitter_programming.md
Normal file
257
08_graphics/blitter_programming.md
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Blitter Programming — Deep Dive
|
||||
|
||||
## Overview
|
||||
|
||||
The **Blitter** (Block Image Transfer) is a DMA engine that performs raster operations on rectangular blocks of memory. It operates on up to **4 channels** (A, B, C → D) using programmable **minterm logic** and can work independently of the CPU. The Blitter is the workhorse for screen clearing, scrolling, cookie-cut sprites, line drawing, and area fill.
|
||||
|
||||
---
|
||||
|
||||
## Channel Architecture
|
||||
|
||||
```
|
||||
Channel A ──→ ┐
|
||||
Channel B ──→ ├──→ Minterm Logic ──→ Channel D (output)
|
||||
Channel C ──→ ┘
|
||||
|
||||
A = mask/pattern (e.g., cookie shape, font glyph)
|
||||
B = source image data
|
||||
C = background / destination read-back
|
||||
D = output destination
|
||||
```
|
||||
|
||||
Each channel reads (or writes, for D) from a different memory pointer with independent modulo.
|
||||
|
||||
---
|
||||
|
||||
## Minterm Logic
|
||||
|
||||
The minterm is an **8-bit truth table** encoding the logical function of A, B, C:
|
||||
|
||||
```
|
||||
Bit 7: ABC = 111 → bit value
|
||||
Bit 6: ABC = 110 → bit value
|
||||
Bit 5: ABC = 101 → bit value
|
||||
Bit 4: ABC = 100 → bit value
|
||||
Bit 3: ABC = 011 → bit value
|
||||
Bit 2: ABC = 010 → bit value
|
||||
Bit 1: ABC = 001 → bit value
|
||||
Bit 0: ABC = 000 → bit value
|
||||
```
|
||||
|
||||
### Common Minterms
|
||||
|
||||
| Minterm | Hex | Operation | Use Case |
|
||||
|---|---|---|---|
|
||||
| `D = A` | `$F0` | Copy A to D | Simple block copy |
|
||||
| `D = B` | `$CC` | Copy B to D | Simple block copy |
|
||||
| `D = C` | `$AA` | Copy C to D | Read-back |
|
||||
| `D = A·B + (¬A)·C` | `$CA` | Cookie-cut | Masked sprite blit (B through A mask onto C) |
|
||||
| `D = 0` | `$00` | Clear | Clear a memory region |
|
||||
| `D = $FFFF` | `$FF` | Set all | Fill with 1s |
|
||||
| `D = A XOR C` | `$5A` | XOR | Cursor blink, highlight |
|
||||
| `D = A OR C` | `$FA` | OR | Overlay |
|
||||
| `D = ¬A AND C` | `$0A` | Mask out | Erase through mask |
|
||||
| `D = A·B` | `$C0` | AND (A,B) | Masked pattern |
|
||||
|
||||
### Cookie-Cut Explained
|
||||
|
||||
```
|
||||
A = mask (1 = sprite pixel, 0 = transparent)
|
||||
B = sprite image data
|
||||
C = background
|
||||
D = result
|
||||
|
||||
Minterm $CA:
|
||||
Where A=1: D = B (show sprite)
|
||||
Where A=0: D = C (show background)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Register Reference
|
||||
|
||||
| Reg | Offset | Description |
|
||||
|---|---|---|
|
||||
| `BLTCON0` | `$040` | Control: channels enabled (bits 11–8), ASH (bits 15–12), minterm (bits 7–0) |
|
||||
| `BLTCON1` | `$042` | Control: BSH (bits 15–12), line mode (bit 0), fill mode (bits 3–2) |
|
||||
| `BLTAFWM` | `$044` | First word mask for channel A |
|
||||
| `BLTALWM` | `$046` | Last word mask for channel A |
|
||||
| `BLTAPT` | `$050` | Channel A pointer (high+low) |
|
||||
| `BLTBPT` | `$04C` | Channel B pointer |
|
||||
| `BLTCPT` | `$048` | Channel C pointer |
|
||||
| `BLTDPT` | `$054` | Channel D pointer |
|
||||
| `BLTAMOD` | `$064` | Channel A modulo |
|
||||
| `BLTBMOD` | `$062` | Channel B modulo |
|
||||
| `BLTCMOD` | `$060` | Channel C modulo |
|
||||
| `BLTDMOD` | `$066` | Channel D modulo |
|
||||
| `BLTSIZE` | `$058` | Blit size + START (write triggers blit) |
|
||||
|
||||
### BLTCON0 Encoding
|
||||
|
||||
```
|
||||
Bits 15–12: ASH (A shift, 0–15 pixels)
|
||||
Bit 11: USEA (enable channel A)
|
||||
Bit 10: USEB (enable channel B)
|
||||
Bit 9: USEC (enable channel C)
|
||||
Bit 8: USED (enable channel D, almost always 1)
|
||||
Bits 7–0: Minterm
|
||||
```
|
||||
|
||||
### BLTSIZE Encoding (OCS/ECS)
|
||||
|
||||
```
|
||||
Bits 15–6: Height in lines (1–1024, 0 means 1024)
|
||||
Bits 5–0: Width in words (1–64, 0 means 64)
|
||||
```
|
||||
|
||||
**Writing BLTSIZE starts the blit!**
|
||||
|
||||
---
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Clear Screen (320×256, 1 bitplane)
|
||||
|
||||
```asm
|
||||
lea $DFF000,a5
|
||||
|
||||
; Wait for blitter idle:
|
||||
.bwait:
|
||||
btst #14,$002(a5) ; DMACONR bit 14 = BBUSY
|
||||
bne.s .bwait
|
||||
|
||||
; D channel only, minterm $00 (clear):
|
||||
move.l #$01000000,$040(a5) ; BLTCON0: USED=1, minterm=$00
|
||||
clr.w $042(a5) ; BLTCON1: 0
|
||||
move.l #ScreenMem,$054(a5) ; BLTDPT
|
||||
clr.w $066(a5) ; BLTDMOD: 0 (contiguous)
|
||||
move.w #(256<<6)|20,$058(a5) ; BLTSIZE: 256 lines × 20 words (320/16)
|
||||
; Blit is now running!
|
||||
```
|
||||
|
||||
### Example 2: Block Copy (No Shift)
|
||||
|
||||
```asm
|
||||
; Copy 64×64 pixel block from source to dest (1 bitplane)
|
||||
; Source and dest are in contiguous bitmap, 320 pixels wide
|
||||
|
||||
; Width = 64 pixels = 4 words
|
||||
; Modulo = (320 - 64) / 16 = 16 words = 32 bytes
|
||||
|
||||
lea $DFF000,a5
|
||||
|
||||
.bwait:
|
||||
btst #14,$002(a5)
|
||||
bne.s .bwait
|
||||
|
||||
move.l #$09F00000,$040(a5) ; BLTCON0: USEA+USED, minterm=$F0 (A→D)
|
||||
clr.w $042(a5) ; BLTCON1
|
||||
move.w #$FFFF,$044(a5) ; BLTAFWM = all bits
|
||||
move.w #$FFFF,$046(a5) ; BLTALWM = all bits
|
||||
move.l #SourceAddr,$050(a5) ; BLTAPT
|
||||
move.l #DestAddr,$054(a5) ; BLTDPT
|
||||
move.w #32,$064(a5) ; BLTAMOD = 32 bytes
|
||||
move.w #32,$066(a5) ; BLTDMOD = 32 bytes
|
||||
move.w #(64<<6)|4,$058(a5) ; BLTSIZE: 64 lines × 4 words → GO!
|
||||
```
|
||||
|
||||
### Example 3: Cookie-Cut Blit (Masked Sprite)
|
||||
|
||||
```asm
|
||||
; Blit a 16×16 masked sprite onto background
|
||||
; A = mask, B = sprite data, C = background, D = destination
|
||||
|
||||
lea $DFF000,a5
|
||||
|
||||
.bwait:
|
||||
btst #14,$002(a5)
|
||||
bne.s .bwait
|
||||
|
||||
move.l #$0FCA0000,$040(a5) ; BLTCON0: A+B+C+D, minterm=$CA
|
||||
clr.w $042(a5) ; BLTCON1
|
||||
move.w #$FFFF,$044(a5) ; BLTAFWM
|
||||
move.w #$FFFF,$046(a5) ; BLTALWM
|
||||
move.l #MaskData,$050(a5) ; BLTAPT = mask
|
||||
move.l #SpriteData,$04C(a5) ; BLTBPT = sprite imagery
|
||||
move.l #ScreenPos,$048(a5) ; BLTCPT = background (read-back)
|
||||
move.l #ScreenPos,$054(a5) ; BLTDPT = same as C (overwrite)
|
||||
clr.w $064(a5) ; BLTAMOD = 0 (mask is 16px = 1 word wide)
|
||||
clr.w $062(a5) ; BLTBMOD = 0
|
||||
move.w #38,$060(a5) ; BLTCMOD = (320-16)/8 = 38 bytes
|
||||
move.w #38,$066(a5) ; BLTDMOD = 38
|
||||
move.w #(16<<6)|1,$058(a5) ; BLTSIZE: 16 lines × 1 word → GO!
|
||||
```
|
||||
|
||||
### Example 4: Line Drawing
|
||||
|
||||
```asm
|
||||
; Draw a line from (x1,y1) to (x2,y2) using blitter line mode
|
||||
; This is complex — blitter line mode uses a Bresenham-style algorithm
|
||||
; implemented in hardware
|
||||
|
||||
; BLTCON1 bit 0 = LINE mode
|
||||
; Channel A = single word (texture pattern)
|
||||
; Channel C/D = destination bitmap
|
||||
|
||||
; See HRM for the full algorithm; here's the concept:
|
||||
move.l #$0B4A0000,$040(a5) ; BLTCON0: A+C+D, minterm=$4A (XOR), ASH=dx
|
||||
move.w #$0001,$042(a5) ; BLTCON1: LINE=1, octant bits set per slope
|
||||
move.w #$8000,$074(a5) ; BLTADAT: single pixel pattern
|
||||
move.w #$FFFF,$044(a5) ; BLTAFWM
|
||||
move.l #StartPos,$048(a5) ; BLTCPT: line start position in bitmap
|
||||
move.l #StartPos,$054(a5) ; BLTDPT: same
|
||||
move.w #Modulo,$060(a5) ; BLTCMOD
|
||||
move.w #Modulo,$066(a5) ; BLTDMOD
|
||||
move.w #(len<<6)|2,$058(a5) ; BLTSIZE: length × 2 → GO!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## System-Friendly Blitter (via graphics.library)
|
||||
|
||||
```c
|
||||
/* BltBitMap — the safe, OS-friendly way: */
|
||||
BltBitMap(srcBitmap, srcX, srcY,
|
||||
dstBitmap, dstX, dstY,
|
||||
width, height,
|
||||
0xC0, /* minterm: A AND B */
|
||||
0xFF, /* all planes */
|
||||
NULL); /* temp buffer */
|
||||
|
||||
/* BltMaskBitMapRastPort — cookie-cut with mask: */
|
||||
BltMaskBitMapRastPort(srcBM, srcX, srcY,
|
||||
rp, dstX, dstY,
|
||||
width, height,
|
||||
(ABC | ABNC | ANBC), /* minterm for cookie */
|
||||
maskPlane);
|
||||
|
||||
/* BltClear — fast memory clear: */
|
||||
BltClear(memory, byteCount, 0);
|
||||
|
||||
/* OwnBlitter / DisownBlitter — exclusive access: */
|
||||
OwnBlitter(); /* wait for and lock blitter */
|
||||
/* ... direct register programming ... */
|
||||
DisownBlitter(); /* release */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Notes
|
||||
|
||||
| Operation | Speed |
|
||||
|---|---|
|
||||
| Word copy | 4 DMA cycles per word (1 µs at 3.58 MHz) |
|
||||
| Full 320×256 clear | ~1280 µs (~1.3 ms) |
|
||||
| Cookie-cut blit | 4 channels = 4 cycles/word (same as copy) |
|
||||
| CPU vs blitter | Blitter wins for moves > ~40 words |
|
||||
| Nasty mode | `BLTPRI` in DMACON: blitter gets priority, CPU stalls |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Blitter* chapter — complete register descriptions
|
||||
- `01_hardware/ocs_a500/blitter.md` — hardware reference
|
||||
- `08_graphics/blitter.md` — graphics.library BltBitMap API
|
||||
124
08_graphics/copper.md
Normal file
124
08_graphics/copper.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Copper — Coprocessor Instructions and UCopList
|
||||
|
||||
## Overview
|
||||
|
||||
The **Copper** is a simple coprocessor in the Amiga custom chips that executes a list of instructions synchronised to the video beam. It can write to any custom chip register at any beam position, enabling per-scanline colour changes, split screens, and hardware-level display effects without CPU intervention.
|
||||
|
||||
---
|
||||
|
||||
## Instruction Format
|
||||
|
||||
The Copper has only three instructions, each 32 bits (one longword):
|
||||
|
||||
### MOVE — Write a Register
|
||||
|
||||
```
|
||||
[register_offset (9 bits)] [value (16 bits)]
|
||||
Bit layout: 0RRRRRRRR00000000 VVVVVVVVVVVVVVVV
|
||||
```
|
||||
|
||||
- Register offset is relative to `$DFF000` (custom chip base)
|
||||
- Only even registers can be written (bit 0 = 0)
|
||||
- Example: `$0180, $0FFF` → write `$0FFF` to `COLOR00` (`$DFF180`)
|
||||
|
||||
### WAIT — Wait for Beam Position
|
||||
|
||||
```
|
||||
[vpos (8 bits)] [hpos (7 bits)] [1] [vmask (7 bits)] [hmask (7 bits)] [0]
|
||||
Bit layout: VVVVVVVVHHHHHH01 vvvvvvvvhhhhhhh0
|
||||
```
|
||||
|
||||
- Pauses until the beam reaches at least the specified (vpos, hpos)
|
||||
- Masks allow waiting on partial positions (e.g. any horizontal, specific vertical)
|
||||
|
||||
### SKIP — Conditional Skip
|
||||
|
||||
```
|
||||
Same as WAIT but bit 0 of second word = 1
|
||||
```
|
||||
|
||||
If the beam has already passed the specified position, skip the next instruction.
|
||||
|
||||
---
|
||||
|
||||
## Standard Copper Patterns
|
||||
|
||||
### Per-Scanline Colour Change (Rainbow)
|
||||
|
||||
```
|
||||
WAIT $2C01,$FFFE ; wait for line $2C (44)
|
||||
MOVE $0180,$0F00 ; COLOR00 = red
|
||||
WAIT $2D01,$FFFE ; wait for line $2D (45)
|
||||
MOVE $0180,$00F0 ; COLOR00 = green
|
||||
WAIT $2E01,$FFFE ; wait for line $2E (46)
|
||||
MOVE $0180,$000F ; COLOR00 = blue
|
||||
...
|
||||
WAIT $FFDF,$FFFE ; wait past line 255 (enables access to lines 256+)
|
||||
WAIT $FFFF,$FFFE ; end-of-list (impossible position = halt)
|
||||
```
|
||||
|
||||
### End of Copper List
|
||||
|
||||
```
|
||||
$FFFF, $FFFE ; WAIT for beam position $FFFF — never reached
|
||||
```
|
||||
|
||||
This is the standard "stop" marker. The Copper loops back to the start on the next vertical blank.
|
||||
|
||||
---
|
||||
|
||||
## System Copper Lists
|
||||
|
||||
The OS manages copper lists through `GfxBase`:
|
||||
|
||||
| Pointer | Description |
|
||||
|---|---|
|
||||
| `GfxBase->copinit` | System initialisation copper list |
|
||||
| `GfxBase->LOFlist` | Long-frame copper list (even fields) |
|
||||
| `GfxBase->SHFlist` | Short-frame copper list (odd fields, interlace) |
|
||||
|
||||
---
|
||||
|
||||
## UCopList — User Copper Instructions
|
||||
|
||||
Applications can inject copper instructions into the system list via `UCopList`:
|
||||
|
||||
```c
|
||||
struct UCopList *ucl = AllocMem(sizeof(struct UCopList), MEMF_PUBLIC|MEMF_CLEAR);
|
||||
|
||||
CINIT(ucl, 100); /* init, max 100 instructions */
|
||||
CWAIT(ucl, 44, 0); /* wait for line 44 */
|
||||
CMOVE(ucl, *((UWORD *)0xDFF180), 0x0F00); /* COLOR00 = red */
|
||||
CWAIT(ucl, 100, 0);
|
||||
CMOVE(ucl, *((UWORD *)0xDFF180), 0x000F); /* COLOR00 = blue */
|
||||
CEND(ucl); /* end of list */
|
||||
|
||||
viewport->UCopIns = ucl;
|
||||
RethinkDisplay(); /* rebuild system copper list */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Chip Register Addresses (Copper-Relevant)
|
||||
|
||||
| Address | Name | Description |
|
||||
|---|---|---|
|
||||
| `$DFF180`–`$DFF1BE` | `COLOR00`–`COLOR31` | OCS/ECS palette (12-bit RGB) |
|
||||
| `$DFF100` | `BPLCON0` | Bitplane control (depth, resolution) |
|
||||
| `$DFF102` | `BPLCON1` | Scroll offsets |
|
||||
| `$DFF104` | `BPLCON2` | Priority control |
|
||||
| `$DFF08E` | `DIWSTRT` | Display window start |
|
||||
| `$DFF090` | `DIWSTOP` | Display window stop |
|
||||
| `$DFF092` | `DDFSTRT` | Data fetch start |
|
||||
| `$DFF094` | `DDFSTOP` | Data fetch stop |
|
||||
| `$DFF0E0`–`$DFF0FE` | `BPL1PT`–`BPL8PT` | Bitplane pointers |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Amiga Hardware Reference Manual* — Copper chapter
|
||||
- NDK39: `graphics/copper.h`, `graphics/gfxmacros.h`
|
||||
- ADCD 2.1: `CINIT`, `CMOVE`, `CWAIT`, `CEND`
|
||||
319
08_graphics/copper_programming.md
Normal file
319
08_graphics/copper_programming.md
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Copper Programming — Deep Dive
|
||||
|
||||
## What Is the Copper?
|
||||
|
||||
The **Copper** (Co-Processor) is a tiny DMA-driven programmable engine inside Agnus (OCS/ECS) or Alice (AGA). It executes a list of instructions — the **copper list** — in lockstep with the video beam as it sweeps across the CRT. Its sole purpose is to write values to custom chip registers at precise screen positions.
|
||||
|
||||
Despite having only **3 instructions** and no arithmetic, branching, or memory read capability, the Copper is what gives the Amiga its distinctive visual character.
|
||||
|
||||
### Where It Lives in the System
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph Agnus/Alice ["Agnus / Alice Chip"]
|
||||
Copper["Copper<br/>(reads copper list via DMA)"]
|
||||
DMA["DMA Controller"]
|
||||
Beam["Beam Counter"]
|
||||
end
|
||||
subgraph Denise/Lisa ["Denise / Lisa Chip"]
|
||||
Palette["Colour Registers"]
|
||||
BPL["Bitplane Control"]
|
||||
SPR["Sprite Control"]
|
||||
end
|
||||
subgraph Memory
|
||||
CopList["Copper List<br/>(Chip RAM only!)"]
|
||||
end
|
||||
|
||||
Beam -- "current V,H position" --> Copper
|
||||
CopList -- "DMA fetch" --> Copper
|
||||
Copper -- "register writes" --> Palette
|
||||
Copper -- "register writes" --> BPL
|
||||
Copper -- "register writes" --> SPR
|
||||
Copper -- "register writes" --> DMA
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- The Copper reads its program from **Chip RAM** via DMA — no CPU involvement
|
||||
- It writes directly to custom chip registers (the same `$DFF000–$DFF1FE` space)
|
||||
- It synchronises with the **beam counter** — it knows exactly where the electron beam is
|
||||
- The CPU can modify the copper list in memory at any time; changes take effect next frame
|
||||
|
||||
### What the Copper Can Do
|
||||
|
||||
| Capability | How | Typical Use |
|
||||
|---|---|---|
|
||||
| **Per-line colour changes** | WAIT for line → MOVE to COLORxx | Gradient skies, rainbow bars, water effects |
|
||||
| **Split-screen displays** | Change bitplane pointers mid-frame | Status bar + scrolling game area |
|
||||
| **Parallax scrolling** | Change BPLCON1 scroll offset at different lines | Multi-layer side-scrollers |
|
||||
| **Resolution mixing** | Change BPLCON0 mid-frame | HiRes title bar + LoRes gameplay |
|
||||
| **Sprite multiplexing** | Repoint sprite DMA pointers after sprite ends | 24+ sprites using 8 physical slots |
|
||||
| **Palette animation** | CPU modifies copper list words each frame | Cycling water, fire, lava |
|
||||
| **Display window shaping** | Change DIWSTRT/DIWSTOP | Overscan, borders, letterbox |
|
||||
| **DMA scheduling** | Enable/disable bitplane/sprite DMA per line | Hide artifacts during setup |
|
||||
|
||||
### What the Copper Cannot Do
|
||||
|
||||
| Limitation | Detail |
|
||||
|---|---|
|
||||
| No arithmetic | Cannot add, subtract, multiply, or compare values |
|
||||
| No branching/loops | Executes linearly top-to-bottom; no jumps or calls |
|
||||
| No memory read | Can only WRITE to registers — cannot read anything |
|
||||
| No CPU memory access | Writes only to custom chip registers (`$DFF000`+), not RAM or CIA |
|
||||
| No sub-pixel timing | Horizontal resolution: 4 colour clocks (~8 low-res pixels) |
|
||||
| V counter wraps at 255 | PAL lines 256–311 require a double-WAIT trick |
|
||||
| Chip RAM only | The copper list itself must reside in Chip RAM (DMA-accessible) |
|
||||
|
||||
### How the System Uses It
|
||||
|
||||
**AmigaOS** — `graphics.library` builds the system copper list automatically when you call `MakeVPort()` / `LoadView()`. This list sets up bitplane pointers, sprite pointers, display window, and palette for every ViewPort. User code adds instructions via `UCopList`.
|
||||
|
||||
**Games (system takeover)** — Disable the OS display system, point COP1LC to your own copper list, and have total control. The copper list typically sets up the display, changes colours per line, and handles sprite multiplexing.
|
||||
|
||||
**Demos** — Push the Copper to its limits: hundreds of colour changes per frame, dynamic copper list generation, and tricks like "copper bars" (changing colours mid-scanline using horizontal WAITs).
|
||||
|
||||
---
|
||||
|
||||
## Instruction Set
|
||||
|
||||
The Copper has exactly **3 instructions**, each 32 bits (2 words):
|
||||
|
||||
### MOVE — Write to Register
|
||||
|
||||
```
|
||||
Word 1: RRRRRRRR R0000000 R = register address (9 bits)
|
||||
Word 2: DDDDDDDD DDDDDDDD D = 16-bit data value
|
||||
|
||||
Constraints:
|
||||
- Register address must be even ($000–$1FE range)
|
||||
- Registers below COPCON threshold ($040) are protected by default
|
||||
- COPCON ($02E) bit 1 can unlock dangerous registers ($000–$03E)
|
||||
```
|
||||
|
||||
**Example:** Set COLOR00 to red
|
||||
```
|
||||
dc.w $0180, $0F00 ; MOVE $0F00 → COLOR00 ($DFF180)
|
||||
```
|
||||
|
||||
### WAIT — Wait for Beam Position
|
||||
|
||||
```
|
||||
Word 1: VVVVVVVV HHHHHHHH V = vertical pos (8 bits), H = horizontal pos
|
||||
Word 2: MMMMMMMM MMMMMM01 M = mask bits, bit 0 = 1 (WAIT marker)
|
||||
|
||||
If bit 15 of word 2 is 0: also blitter-finished wait
|
||||
Default mask: $FFFE (match all V and H bits except bit 0)
|
||||
```
|
||||
|
||||
**Example:** Wait for line 100, any horizontal position
|
||||
```
|
||||
dc.w $6401, $FFFE ; WAIT V=$64 (100), H=$01
|
||||
```
|
||||
|
||||
### SKIP — Conditional Skip
|
||||
|
||||
```
|
||||
Word 1: VVVVVVVV HHHHHHHH same format as WAIT
|
||||
Word 2: MMMMMMMM MMMMMM11 bit 0 = 1, bit 1 = 1 (SKIP marker)
|
||||
|
||||
If beam position ≥ specified position, skip next instruction.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Beam Position Encoding
|
||||
|
||||
```
|
||||
Vertical: bits 15–8 of word 1 = V7–V0 (range 0–255)
|
||||
For PAL lines > 255, use WAIT twice or the LOF bit
|
||||
Horizontal: bits 7–1 of word 1 = H8–H1 (range 0–$E2, step 2)
|
||||
Bit 0 always 0 in WAIT word 1 (distinguishes from MOVE)
|
||||
|
||||
Full PAL: 312 lines, but copper V wraps at 256
|
||||
Lines 0–255: V = line number
|
||||
Lines 256+: V wraps; use two WAITs:
|
||||
WAIT for V=$FF (end of first field)
|
||||
WAIT for actual line - 256
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Copper List Termination
|
||||
|
||||
```
|
||||
; End-of-list sentinel (wait for impossible position):
|
||||
dc.w $FFFF, $FFFE ; WAIT $FF,$FF — never reached
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Example 1: Rainbow Bars (Colour Per Scanline)
|
||||
|
||||
```asm
|
||||
; copperlist.s — 256-colour rainbow using Copper
|
||||
SECTION copperlist,DATA_C ; MUST be in Chip RAM!
|
||||
|
||||
CopperList:
|
||||
; Set up a basic display first
|
||||
dc.w $0100, $1200 ; BPLCON0: 1 bitplane, colour on
|
||||
dc.w $0092, $0038 ; DDFSTRT
|
||||
dc.w $0094, $00D0 ; DDFSTOP
|
||||
dc.w $008E, $2C81 ; DIWSTRT
|
||||
dc.w $0090, $2CC1 ; DIWSTOP
|
||||
|
||||
; Line 44 ($2C): start of visible display
|
||||
dc.w $2C01, $FFFE ; WAIT line 44
|
||||
dc.w $0180, $0F00 ; COLOR00 = bright red
|
||||
|
||||
dc.w $2D01, $FFFE ; WAIT line 45
|
||||
dc.w $0180, $0E10 ; COLOR00 = red-orange
|
||||
|
||||
dc.w $2E01, $FFFE ; WAIT line 46
|
||||
dc.w $0180, $0D20 ; COLOR00 = orange
|
||||
|
||||
dc.w $2F01, $FFFE ; WAIT line 47
|
||||
dc.w $0180, $0C30 ; COLOR00 = yellow-orange
|
||||
|
||||
; ... repeat for each line with incrementing colours ...
|
||||
|
||||
dc.w $FFFF, $FFFE ; end of copper list
|
||||
|
||||
SECTION code,CODE
|
||||
|
||||
start:
|
||||
move.l 4.w,a6 ; SysBase
|
||||
lea $DFF000,a5 ; custom chips base
|
||||
|
||||
; Install copper list:
|
||||
move.l #CopperList,$080(a5) ; COP1LCH/COP1LCL
|
||||
move.w #0,$088(a5) ; COPJMP1 — strobe to restart
|
||||
|
||||
; Enable DMA:
|
||||
move.w #$8280,$096(a5) ; DMACON: SET + COPEN + DMAEN
|
||||
|
||||
.wait:
|
||||
btst #6,$BFE001 ; left mouse button
|
||||
bne.s .wait
|
||||
rts
|
||||
```
|
||||
|
||||
### Example 2: Split Screen (Two Different Backgrounds)
|
||||
|
||||
```asm
|
||||
SplitCopperList:
|
||||
; Top half: blue background
|
||||
dc.w $0180, $000F ; COLOR00 = blue
|
||||
|
||||
; Wait for middle of screen (line 128)
|
||||
dc.w $8001, $FFFE ; WAIT line $80 = 128
|
||||
|
||||
; Bottom half: green background
|
||||
dc.w $0180, $00F0 ; COLOR00 = green
|
||||
|
||||
dc.w $FFFF, $FFFE ; end
|
||||
```
|
||||
|
||||
### Example 3: Parallax Scrolling via Copper
|
||||
|
||||
```asm
|
||||
ParallaxCopperList:
|
||||
; Background layer: scroll position 0
|
||||
dc.w $0102, $0000 ; BPLCON1 = no scroll
|
||||
|
||||
; Wait for horizon line
|
||||
dc.w $6001, $FFFE ; WAIT line 96
|
||||
|
||||
; Middle layer: scroll by 2 pixels
|
||||
dc.w $0102, $0022 ; BPLCON1 = scroll 2px both playfields
|
||||
|
||||
; Wait for ground layer
|
||||
dc.w $A001, $FFFE ; WAIT line 160
|
||||
|
||||
; Ground layer: scroll by 4 pixels
|
||||
dc.w $0102, $0044 ; BPLCON1 = scroll 4px
|
||||
|
||||
dc.w $FFFF, $FFFE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## System-Friendly Copper (via graphics.library)
|
||||
|
||||
For programs that coexist with the OS:
|
||||
|
||||
```c
|
||||
#include <graphics/copper.h>
|
||||
|
||||
/* Allocate a user copper list: */
|
||||
struct UCopList *ucl = AllocMem(sizeof(struct UCopList), MEMF_CLEAR);
|
||||
|
||||
/* Build instructions: */
|
||||
CINIT(ucl, 100); /* init, max 100 instructions */
|
||||
CWAIT(ucl, 0, 0); /* wait for top of display */
|
||||
CMOVE(ucl, custom.color[0], 0x00F); /* set COLOR00 = blue */
|
||||
CWAIT(ucl, 128, 0); /* wait for line 128 */
|
||||
CMOVE(ucl, custom.color[0], 0x0F0); /* set COLOR00 = green */
|
||||
CEND(ucl); /* end */
|
||||
|
||||
/* Install on ViewPort: */
|
||||
vp->UCopIns = ucl;
|
||||
RethinkDisplay(); /* rebuild system copper list with our additions */
|
||||
|
||||
/* Cleanup: */
|
||||
vp->UCopIns = NULL;
|
||||
RethinkDisplay();
|
||||
FreeVPortCopLists(vp);
|
||||
FreeCopList(ucl);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Copper Timing
|
||||
|
||||
| Item | Cycles |
|
||||
|---|---|
|
||||
| Each Copper instruction | 4 colour clocks (= 8 low-res pixels) |
|
||||
| WAIT resolution (horizontal) | 4 colour clocks minimum |
|
||||
| Maximum instructions per line | ~112 (NTSC) / ~114 (PAL) |
|
||||
| PAL visible lines | 256 (lines 44–300) |
|
||||
| NTSC visible lines | 200 (lines 44–244) |
|
||||
|
||||
---
|
||||
|
||||
## Advanced Techniques
|
||||
|
||||
### Copper-Driven Sprite Multiplexing
|
||||
|
||||
Reposition sprites mid-frame to display more than 8 sprites:
|
||||
|
||||
```asm
|
||||
; Display sprite 0 at Y=50
|
||||
dc.w $3001, $FFFE ; WAIT line 48 (before sprite)
|
||||
dc.w $0120, SprData1>>16 ; SPR0PTH
|
||||
dc.w $0122, SprData1&$FFFF ; SPR0PTL
|
||||
|
||||
; After sprite 0 finishes at Y=66, reuse for position Y=100
|
||||
dc.w $6801, $FFFE ; WAIT line 104
|
||||
dc.w $0120, SprData2>>16 ; SPR0PTH — repoint to different data
|
||||
dc.w $0122, SprData2&$FFFF ; SPR0PTL
|
||||
```
|
||||
|
||||
### Copper-Driven Palette Animation
|
||||
|
||||
```asm
|
||||
; Animate copper list by modifying colour values each frame
|
||||
; (DMA reads new values each frame automatically)
|
||||
; Just update the data words in the copper list in Chip RAM
|
||||
move.w d0, CopperList+6 ; modify the MOVE data word
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Copper* chapter — complete instruction encoding
|
||||
- `01_hardware/ocs_a500/copper.md` — register-level reference
|
||||
- `08_graphics/copper.md` — graphics.library UCopList API
|
||||
74
08_graphics/display_modes.md
Normal file
74
08_graphics/display_modes.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Display Modes — Display Database, ModeID, Monitor Specs
|
||||
|
||||
## Overview
|
||||
|
||||
OS 3.0+ provides a **display database** that abstracts monitor/chipset capabilities. Applications query available modes by `ModeID` rather than hardcoding `HIRES`/`LACE` flags.
|
||||
|
||||
---
|
||||
|
||||
## ModeID Format
|
||||
|
||||
A ModeID is a ULONG:
|
||||
```
|
||||
bits 31–16: Monitor ID
|
||||
bits 15–0: Mode within that monitor
|
||||
```
|
||||
|
||||
| ModeID | Name | Resolution |
|
||||
|---|---|---|
|
||||
| `$00000000` | LORES | 320×256 (PAL) / 320×200 (NTSC) |
|
||||
| `$00008000` | HIRES | 640×256/200 |
|
||||
| `$00000004` | LORES-LACE | 320×512/400 |
|
||||
| `$00008004` | HIRES-LACE | 640×512/400 |
|
||||
| `$00080000` | SUPERHIRES | 1280×256 (ECS+) |
|
||||
| `$00080004` | SUPERHIRES-LACE | 1280×512 |
|
||||
| `$00039000` | DBLPAL-LORES | 320×256 (AGA scan-doubled) |
|
||||
| `$00039004` | DBLPAL-HIRES | 640×256 (AGA) |
|
||||
| `$00011000` | DBLNTSC-LORES | 320×200 (AGA) |
|
||||
|
||||
---
|
||||
|
||||
## Querying the Display Database
|
||||
|
||||
```c
|
||||
/* graphics.library 39+ */
|
||||
ULONG modeID = INVALID_ID;
|
||||
struct DisplayInfo di;
|
||||
struct DimensionInfo dims;
|
||||
|
||||
while ((modeID = NextDisplayInfo(modeID)) != INVALID_ID) {
|
||||
if (GetDisplayInfoData(NULL, (UBYTE *)&di, sizeof(di),
|
||||
DTAG_DISP, modeID)) {
|
||||
if (GetDisplayInfoData(NULL, (UBYTE *)&dims, sizeof(dims),
|
||||
DTAG_DIMS, modeID)) {
|
||||
Printf("ModeID $%08lx: %ldx%ld, %ld colours\n",
|
||||
modeID,
|
||||
dims.Nominal.MaxX - dims.Nominal.MinX + 1,
|
||||
dims.Nominal.MaxY - dims.Nominal.MinY + 1,
|
||||
1 << di.NotAvailable ? 0 : dims.MaxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Mode Selection
|
||||
|
||||
```c
|
||||
ULONG bestMode = BestModeIDA((struct TagItem[]){
|
||||
{ BIDTAG_NominalWidth, 640 },
|
||||
{ BIDTAG_NominalHeight, 480 },
|
||||
{ BIDTAG_Depth, 8 },
|
||||
{ TAG_DONE, 0 }
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/displayinfo.h`, `graphics/modeid.h`
|
||||
- ADCD 2.1: `NextDisplayInfo`, `GetDisplayInfoData`, `BestModeIDA`
|
||||
90
08_graphics/gfx_base.md
Normal file
90
08_graphics/gfx_base.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# GfxBase — Graphics Library Global State
|
||||
|
||||
## Overview
|
||||
|
||||
`graphics.library` manages all display output, drawing primitives, and custom chip programming. `GfxBase` is the library base containing display state, chip revision info, and the system copper lists.
|
||||
|
||||
---
|
||||
|
||||
## struct GfxBase (Key Fields)
|
||||
|
||||
```c
|
||||
/* graphics/gfxbase.h — NDK39 */
|
||||
struct GfxBase {
|
||||
struct Library LibNode;
|
||||
struct View *ActiView; /* currently active View */
|
||||
struct copinit *copinit; /* system copper list init */
|
||||
LONG *cia; /* CIA base (deprecated) */
|
||||
LONG *blitter; /* blitter base (deprecated) */
|
||||
UWORD *LOFlist; /* long-frame copper list pointer */
|
||||
UWORD *SHFlist; /* short-frame copper list (interlace) */
|
||||
struct bltnode *blthd; /* blitter queue head */
|
||||
struct bltnode *blttl; /* blitter queue tail */
|
||||
struct bltnode *bsblthd;
|
||||
struct bltnode *bsblttl;
|
||||
struct Interrupt vbsrv; /* vertical blank server list */
|
||||
struct Interrupt timsrv;
|
||||
struct Interrupt bltsrv;
|
||||
struct List TextFonts; /* system font list */
|
||||
struct TextFont *DefaultFont; /* default system font */
|
||||
UWORD Modes; /* current display mode bits */
|
||||
BYTE VBlankFrequency; /* 50 (PAL) or 60 (NTSC) */
|
||||
BYTE DisplayFlags; /* PAL/NTSC/GENLOCK flags */
|
||||
UWORD NormalDisplayColumns;
|
||||
UWORD NormalDisplayRows;
|
||||
UWORD MaxDisplayColumn;
|
||||
UWORD MaxDisplayRow;
|
||||
UWORD ChipRevBits0; /* chip revision flags */
|
||||
/* ... many more fields ... */
|
||||
struct MonitorSpec *monitor_id;
|
||||
struct List MonitorList;
|
||||
struct List ModesList; /* display mode database */
|
||||
UBYTE MemType; /* memory type flags */
|
||||
/* OS 3.x additions */
|
||||
APTR ChunkyToPlanarPtr; /* c2p conversion routine */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chip Revision Detection
|
||||
|
||||
```c
|
||||
/* graphics/gfxbase.h */
|
||||
#define GFXB_BIG_BLITS 0 /* big blitter (ECS Agnus) */
|
||||
#define GFXB_HR_AGNUS 0 /* same — hi-res Agnus */
|
||||
#define GFXB_HR_DENISE 1 /* ECS Denise (SuperHires, scan-doubling) */
|
||||
#define GFXB_AA_ALICE 2 /* AGA Alice (A1200/A4000) */
|
||||
#define GFXB_AA_LISA 3 /* AGA Lisa */
|
||||
#define GFXB_AA_MLISA 4 /* AGA Lisa (modified) */
|
||||
|
||||
#define GFXF_BIG_BLITS (1<<0)
|
||||
#define GFXF_HR_AGNUS (1<<0)
|
||||
#define GFXF_HR_DENISE (1<<1)
|
||||
#define GFXF_AA_ALICE (1<<2)
|
||||
#define GFXF_AA_LISA (1<<3)
|
||||
#define GFXF_AA_MLISA (1<<4)
|
||||
|
||||
/* Check for AGA: */
|
||||
if (GfxBase->ChipRevBits0 & GFXF_AA_ALICE) {
|
||||
/* AGA chipset — 8-bit planar, 256 colours in indexed mode */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PAL vs NTSC
|
||||
|
||||
```c
|
||||
if (GfxBase->VBlankFrequency == 50) /* PAL: 50Hz, 625 lines */
|
||||
if (GfxBase->VBlankFrequency == 60) /* NTSC: 60Hz, 525 lines */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/gfxbase.h`
|
||||
- ADCD 2.1: graphics.library autodocs
|
||||
134
08_graphics/ham_ehb_modes.md
Normal file
134
08_graphics/ham_ehb_modes.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# HAM and EHB — Special Display Modes
|
||||
|
||||
## Overview
|
||||
|
||||
The Amiga offers two unique display modes that squeeze many more colours from limited bitplane hardware: **EHB** (Extra Half-Brite) and **HAM** (Hold-And-Modify). These modes have no direct equivalent on other platforms and are critical for understanding Amiga graphics capability.
|
||||
|
||||
---
|
||||
|
||||
## EHB — Extra Half-Brite (OCS/ECS/AGA)
|
||||
|
||||
### How It Works
|
||||
|
||||
Uses **6 bitplanes** (64 possible values):
|
||||
- Bitplane values 0–31: index into the 32-colour palette normally
|
||||
- Bitplane values 32–63: display the colour from register (value − 32) at **half brightness** (all RGB components halved)
|
||||
|
||||
```
|
||||
Bitplanes 0–4 → 5-bit colour index (0–31)
|
||||
Bitplane 5 → "half brightness" flag
|
||||
```
|
||||
|
||||
### Effective Result
|
||||
|
||||
- 32 programmer-defined colours + 32 fixed half-brightness versions = **64 colours**
|
||||
- Zero additional palette RAM needed
|
||||
- Useful for shadows and smooth gradients
|
||||
|
||||
### Enabling EHB
|
||||
|
||||
```c
|
||||
/* In ViewPort ColorMap: */
|
||||
/* Simply use 6 bitplanes with no HAM flag */
|
||||
struct BitMap bm;
|
||||
InitBitMap(&bm, 6, 320, 256); /* 6 planes */
|
||||
/* No EXTRA_HALFBRITE flag needed — it's automatic when depth=6 */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## HAM — Hold-And-Modify (OCS/ECS)
|
||||
|
||||
### How It Works
|
||||
|
||||
Uses **6 bitplanes**. Each pixel's 6 bits are interpreted as:
|
||||
|
||||
| Bits 5–4 | Meaning | Bits 3–0 |
|
||||
|---|---|---|
|
||||
| `00` | **SET** — index colour register | 4-bit palette index (0–15) |
|
||||
| `01` | **MODIFY BLUE** — hold R,G; set B | New blue nibble |
|
||||
| `10` | **MODIFY RED** — hold G,B; set R | New red nibble |
|
||||
| `11` | **MODIFY GREEN** — hold R,B; set G | New green nibble |
|
||||
|
||||
### Effective Result
|
||||
|
||||
- Each pixel can set one of 16 base colours, OR modify one component of the previous pixel's colour
|
||||
- Theoretical maximum: **4,096 colours** on screen simultaneously
|
||||
- Practical result: colour fringing at sharp edges (each pixel depends on its left neighbour)
|
||||
|
||||
### OCS/ECS Limitations
|
||||
|
||||
- Only 16 base colours (SET mode uses 4 bits → 16 palette entries)
|
||||
- Only 4-bit component modification → 16 levels per channel
|
||||
- Total colour space: 12-bit (4096 colours)
|
||||
|
||||
---
|
||||
|
||||
## HAM8 — AGA Enhanced HAM
|
||||
|
||||
### How It Works
|
||||
|
||||
Uses **8 bitplanes**:
|
||||
|
||||
| Bits 7–6 | Meaning | Bits 5–0 |
|
||||
|---|---|---|
|
||||
| `00` | **SET** — index colour register | 6-bit palette index (0–63) |
|
||||
| `01` | **MODIFY BLUE** | 6-bit blue value |
|
||||
| `10` | **MODIFY RED** | 6-bit red value |
|
||||
| `11` | **MODIFY GREEN** | 6-bit green value |
|
||||
|
||||
### Effective Result
|
||||
|
||||
- 64 base colours from the 256-entry palette
|
||||
- 6-bit component modification → 64 levels per channel
|
||||
- Total colour space: **18-bit** (262,144 colours)
|
||||
- Significantly reduced fringing compared to HAM6
|
||||
|
||||
### HAM8 Memory Layout
|
||||
|
||||
```
|
||||
8 bitplanes × 320 pixels × 256 lines = 81,920 bytes per plane × 8
|
||||
= 655,360 bytes (640 KB) for a single HAM8 320×256 display
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enabling HAM
|
||||
|
||||
```c
|
||||
/* Via ViewPort: */
|
||||
vp->Modes |= HAM; /* HAMF flag in modes */
|
||||
|
||||
/* Via SA_ tags (Intuition screen): */
|
||||
struct TagItem scrTags[] = {
|
||||
{ SA_Width, 320 },
|
||||
{ SA_Height, 256 },
|
||||
{ SA_Depth, 6 }, /* 6 for HAM6, 8 for HAM8 */
|
||||
{ SA_DisplayID, HAM_KEY }, /* or SUPER_KEY|HAM for Super-HiRes HAM */
|
||||
{ TAG_DONE, 0 }
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison Table
|
||||
|
||||
| Feature | EHB | HAM6 | HAM8 |
|
||||
|---|---|---|---|
|
||||
| Bitplanes | 6 | 6 | 8 |
|
||||
| Chipset | OCS/ECS/AGA | OCS/ECS/AGA | AGA only |
|
||||
| Base palette | 32 | 16 | 64 |
|
||||
| Max on-screen colours | 64 | 4,096 | 262,144 |
|
||||
| Colour depth | 12-bit | 12-bit | 24-bit (via 18-bit HAM) |
|
||||
| Fringing | None | Significant | Mild |
|
||||
| Good for | GUI, sprites | Photos, static art | Photos, video stills |
|
||||
| Bad for | — | Animation, scrolling | Memory-hungry |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Display modes* chapter
|
||||
- NDK39: `graphics/displayinfo.h` — `HAM_KEY`, `EXTRAHALFBRITE_KEY`
|
||||
112
08_graphics/rastport.md
Normal file
112
08_graphics/rastport.md
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# RastPort — Drawing Primitives and Layers
|
||||
|
||||
## Overview
|
||||
|
||||
`RastPort` is the primary drawing context in AmigaOS. All graphics primitives (pixel, line, rectangle, polygon, text) operate through a `RastPort`, which links a `BitMap`, drawing pen colours, pattern, font, and optional `Layer` for clipping.
|
||||
|
||||
---
|
||||
|
||||
## struct RastPort
|
||||
|
||||
```c
|
||||
/* 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 colour index */
|
||||
BYTE BgPen; /* background pen colour 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
|
||||
|
||||
```c
|
||||
#define JAM1 0 /* draw FgPen only; background transparent */
|
||||
#define JAM2 1 /* draw FgPen and BgPen (opaque) */
|
||||
#define COMPLEMENT 2 /* XOR with existing pixels */
|
||||
#define INVERSVID 4 /* invert video (swap fg/bg for text) */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Drawing Primitives
|
||||
|
||||
```c
|
||||
/* Set pen colour: */
|
||||
SetAPen(rp, 1); /* foreground = colour 1 */
|
||||
SetBPen(rp, 0); /* background = colour 0 */
|
||||
SetDrMd(rp, JAM1); /* transparent background */
|
||||
|
||||
/* Move to position: */
|
||||
Move(rp, 100, 50);
|
||||
|
||||
/* Draw line from current position to (x,y): */
|
||||
Draw(rp, 200, 100);
|
||||
|
||||
/* Write pixel: */
|
||||
WritePixel(rp, 160, 120);
|
||||
|
||||
/* Read pixel: */
|
||||
LONG colour = ReadPixel(rp, 160, 120);
|
||||
|
||||
/* Filled rectangle: */
|
||||
RectFill(rp, 10, 10, 100, 50);
|
||||
|
||||
/* Draw text at current position: */
|
||||
Move(rp, 20, 30);
|
||||
Text(rp, "Hello", 5);
|
||||
|
||||
/* Blitter copy between RastPorts: */
|
||||
ClipBlit(srcRP, sx, sy, dstRP, dx, dy, w, h, minterm);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layers
|
||||
|
||||
When `rp->Layer != NULL`, all drawing is clipped to the layer's bounds and damage regions. Layers are managed by `layers.library`:
|
||||
|
||||
```c
|
||||
struct Layer_Info *li = NewLayerInfo();
|
||||
struct Layer *layer = CreateUpfrontLayer(li, bm, x1, y1, x2, y2, flags, NULL);
|
||||
rp = layer->rp; /* use this RastPort for drawing */
|
||||
/* ... draw ... */
|
||||
DeleteLayer(0, layer);
|
||||
DisposeLayerInfo(li);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/rastport.h`, `graphics/gfxmacros.h`
|
||||
- ADCD 2.1: `SetAPen`, `Move`, `Draw`, `Text`, `RectFill`, `ClipBlit`
|
||||
102
08_graphics/sprites.md
Normal file
102
08_graphics/sprites.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Hardware Sprites — SimpleSprite, MoveSprite
|
||||
|
||||
## Overview
|
||||
|
||||
The Amiga has **8 hardware sprites**, each 16 pixels wide with 3 colours + transparent. Sprites are DMA-driven — the Copper sets their pointers each frame and the display hardware renders them with zero CPU overhead.
|
||||
|
||||
---
|
||||
|
||||
## Sprite DMA Data Format
|
||||
|
||||
Each sprite scanline is two words (4 bytes):
|
||||
|
||||
```
|
||||
Word 0 (DATA): bits 15–0 = pixel colour bit 0 for this line
|
||||
Word 1 (DATB): bits 15–0 = pixel colour bit 1 for this line
|
||||
|
||||
Pixel colour = (DATB_bit << 1) | DATA_bit
|
||||
00 = transparent
|
||||
01 = colour 1 (from sprite palette)
|
||||
10 = colour 2
|
||||
11 = colour 3
|
||||
```
|
||||
|
||||
### Sprite Header
|
||||
|
||||
```
|
||||
WORD 0: VSTART (vertical start position) + HSTART high bits
|
||||
WORD 1: VSTOP (vertical stop position) + control bits
|
||||
```
|
||||
|
||||
### End marker
|
||||
```
|
||||
WORD 0: 0x0000
|
||||
WORD 1: 0x0000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sprite Colour Palette
|
||||
|
||||
| Sprite pair | Colour registers | Custom addresses |
|
||||
|---|---|---|
|
||||
| 0–1 | `COLOR17`–`COLOR19` | `$DFF1A2`–`$DFF1A6` |
|
||||
| 2–3 | `COLOR21`–`COLOR23` | `$DFF1AA`–`$DFF1AE` |
|
||||
| 4–5 | `COLOR25`–`COLOR27` | `$DFF1B2`–`$DFF1B6` |
|
||||
| 6–7 | `COLOR29`–`COLOR31` | `$DFF1BA`–`$DFF1BE` |
|
||||
|
||||
Sprite pairs can be **attached** to form a single 15-colour sprite (using both sets of 2 bits = 4 bits per pixel).
|
||||
|
||||
---
|
||||
|
||||
## OS-Level Sprite API
|
||||
|
||||
```c
|
||||
/* graphics.library */
|
||||
struct SimpleSprite ss;
|
||||
WORD sprnum;
|
||||
|
||||
/* Obtain a free sprite: */
|
||||
sprnum = GetSprite(&ss, -1); /* -1 = any available */
|
||||
if (sprnum >= 0) {
|
||||
ss.x = 100;
|
||||
ss.y = 50;
|
||||
ss.height = 16;
|
||||
|
||||
/* Move sprite to position: */
|
||||
MoveSprite(NULL, &ss, 100, 50);
|
||||
|
||||
/* Set sprite image data: */
|
||||
ChangeSprite(NULL, &ss, spriteData);
|
||||
|
||||
/* Release: */
|
||||
FreeSprite(sprnum);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sprite Pointer Registers
|
||||
|
||||
| Register | Address | Sprite |
|
||||
|---|---|---|
|
||||
| `SPR0PTH/L` | `$DFF120–$DFF122` | Sprite 0 |
|
||||
| `SPR1PTH/L` | `$DFF124–$DFF126` | Sprite 1 |
|
||||
| `SPR2PTH/L` | `$DFF128–$DFF12A` | Sprite 2 |
|
||||
| `SPR3PTH/L` | `$DFF12C–$DFF12E` | Sprite 3 |
|
||||
| `SPR4PTH/L` | `$DFF130–$DFF132` | Sprite 4 |
|
||||
| `SPR5PTH/L` | `$DFF134–$DFF136` | Sprite 5 |
|
||||
| `SPR6PTH/L` | `$DFF138–$DFF13A` | Sprite 6 |
|
||||
| `SPR7PTH/L` | `$DFF13C–$DFF13E` | Sprite 7 |
|
||||
|
||||
These must be set every frame — typically via the Copper list.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Amiga Hardware Reference Manual* — Sprites chapter
|
||||
- NDK39: `graphics/sprite.h`
|
||||
- ADCD 2.1: `GetSprite`, `MoveSprite`, `ChangeSprite`, `FreeSprite`
|
||||
90
08_graphics/text_fonts.md
Normal file
90
08_graphics/text_fonts.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Text and Fonts — TextFont, TextAttr, OpenFont, Text
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaOS uses bitmap fonts rendered through `graphics.library`. Fonts are described by `TextAttr` (request) and `TextFont` (loaded instance). Disk fonts require `diskfont.library`.
|
||||
|
||||
---
|
||||
|
||||
## Key Structures
|
||||
|
||||
```c
|
||||
/* graphics/text.h — NDK39 */
|
||||
struct TextAttr {
|
||||
STRPTR ta_Name; /* font name, e.g. "topaz.font" */
|
||||
UWORD ta_YSize; /* desired height in pixels */
|
||||
UBYTE ta_Style; /* FSF_BOLD, FSF_ITALIC, FSF_UNDERLINED */
|
||||
UBYTE ta_Flags; /* FPF_ROMFONT, FPF_DISKFONT, etc. */
|
||||
};
|
||||
|
||||
struct TextFont {
|
||||
struct Message tf_Message;
|
||||
UWORD tf_YSize; /* font height */
|
||||
UBYTE tf_Style;
|
||||
UBYTE tf_Flags;
|
||||
UWORD tf_XSize; /* nominal width */
|
||||
UWORD tf_Baseline; /* baseline from top */
|
||||
UWORD tf_BoldSmear; /* bold smear width */
|
||||
UWORD tf_Accessors; /* open count */
|
||||
UBYTE tf_LoChar; /* first character code */
|
||||
UBYTE tf_HiChar; /* last character code */
|
||||
APTR tf_CharData; /* bitmap data */
|
||||
UWORD tf_Modulo; /* bytes per row of font bitmap */
|
||||
APTR tf_CharLoc; /* character location table */
|
||||
APTR tf_CharSpace; /* proportional spacing table */
|
||||
APTR tf_CharKern; /* kerning table */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Opening Fonts
|
||||
|
||||
```c
|
||||
/* ROM font (topaz, always available): */
|
||||
struct TextAttr ta = {"topaz.font", 8, 0, FPF_ROMFONT};
|
||||
struct TextFont *font = OpenFont(&ta);
|
||||
|
||||
/* Disk font (requires diskfont.library): */
|
||||
struct TextAttr ta2 = {"helvetica.font", 24, 0, FPF_DISKFONT};
|
||||
struct TextFont *font2 = OpenDiskFont(&ta2);
|
||||
|
||||
/* Set in RastPort: */
|
||||
SetFont(rp, font);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rendering Text
|
||||
|
||||
```c
|
||||
Move(rp, 10, 20); /* position cursor */
|
||||
Text(rp, "Hello Amiga", 11); /* render 11 characters */
|
||||
|
||||
/* Get pixel width of a string: */
|
||||
UWORD width = TextLength(rp, "Hello", 5);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Style Flags
|
||||
|
||||
```c
|
||||
#define FSF_UNDERLINED 0x01
|
||||
#define FSF_BOLD 0x02
|
||||
#define FSF_ITALIC 0x04
|
||||
#define FSF_EXTENDED 0x08
|
||||
|
||||
/* Set algorithmic style: */
|
||||
SetSoftStyle(rp, FSF_BOLD | FSF_ITALIC,
|
||||
AskSoftStyle(rp)); /* ask which styles the font supports */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/text.h`
|
||||
- ADCD 2.1: `OpenFont`, `OpenDiskFont`, `SetFont`, `Text`, `TextLength`
|
||||
109
08_graphics/views.md
Normal file
109
08_graphics/views.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
[← Home](../README.md) · [Graphics](README.md)
|
||||
|
||||
# Views and ViewPorts — Display Construction
|
||||
|
||||
## Overview
|
||||
|
||||
The AmigaOS display system builds the actual screen image through a hierarchy: `View` → `ViewPort` → `RasInfo` → `BitMap`. The `MakeVPort`/`MrgCop`/`LoadView` pipeline compiles this into a Copper list that programs the custom chips.
|
||||
|
||||
---
|
||||
|
||||
## Key Structures
|
||||
|
||||
```c
|
||||
/* graphics/view.h — NDK39 */
|
||||
struct View {
|
||||
struct ViewPort *ViewPort; /* first viewport in chain */
|
||||
struct cprlist *LOFCprList; /* long-frame copper list */
|
||||
struct cprlist *SHFCprList; /* short-frame copper list */
|
||||
WORD DyOffset; /* vertical scroll offset */
|
||||
WORD DxOffset; /* horizontal scroll offset */
|
||||
UWORD Modes; /* display mode flags */
|
||||
};
|
||||
|
||||
struct ViewPort {
|
||||
struct ViewPort *Next; /* next viewport in chain */
|
||||
struct ColorMap *ColorMap; /* palette for this viewport */
|
||||
struct CopList *DspIns; /* display copper instructions */
|
||||
struct CopList *SprIns; /* sprite copper instructions */
|
||||
struct CopList *ClrIns; /* colour copper instructions */
|
||||
struct CopList *UCopIns; /* user copper instructions */
|
||||
WORD DWidth; /* display width */
|
||||
WORD DHeight; /* display height */
|
||||
WORD DxOffset;
|
||||
WORD DyOffset;
|
||||
UWORD Modes; /* HIRES, LACE, HAM, EHB, etc. */
|
||||
UBYTE SpritePriorities;
|
||||
UBYTE ExtendedModes;
|
||||
struct RasInfo *RasInfo; /* linked bitmap info */
|
||||
};
|
||||
|
||||
struct RasInfo {
|
||||
struct RasInfo *Next; /* for dual-playfield */
|
||||
struct BitMap *BitMap; /* the actual bitmap */
|
||||
WORD RxOffset; /* horizontal scroll within bitmap */
|
||||
WORD RyOffset; /* vertical scroll within bitmap */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Display Mode Flags
|
||||
|
||||
```c
|
||||
/* graphics/view.h */
|
||||
#define HIRES 0x8000 /* 640 pixel mode */
|
||||
#define LACE 0x0004 /* interlaced */
|
||||
#define HAM 0x0800 /* Hold-And-Modify (4096 colours) */
|
||||
#define EXTRA_HALFBRITE 0x0080 /* Extra Half-Brite (64 colours) */
|
||||
#define DUALPF 0x0400 /* dual playfield */
|
||||
#define PFBA 0x0040 /* playfield B has priority */
|
||||
#define SUPERHIRES 0x0020 /* 1280 pixel mode (ECS+) */
|
||||
#define VP_HIDE 0x2000 /* viewport is hidden */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Building a Display
|
||||
|
||||
```c
|
||||
struct View view;
|
||||
struct ViewPort vp;
|
||||
struct RasInfo ri;
|
||||
struct BitMap *bm = AllocBitMap(320, 256, 5, BMF_DISPLAYABLE|BMF_CLEAR, NULL);
|
||||
|
||||
InitView(&view);
|
||||
InitVPort(&vp);
|
||||
view.ViewPort = &vp;
|
||||
vp.RasInfo = &ri;
|
||||
ri.BitMap = bm;
|
||||
vp.DWidth = 320;
|
||||
vp.DHeight = 256;
|
||||
vp.Modes = 0; /* lores */
|
||||
|
||||
/* Build colour map: */
|
||||
vp.ColorMap = GetColorMap(32);
|
||||
|
||||
/* Compile to copper: */
|
||||
MakeVPort(&view, &vp);
|
||||
MrgCop(&view);
|
||||
|
||||
/* Activate: */
|
||||
LoadView(&view);
|
||||
WaitTOF();
|
||||
|
||||
/* Cleanup: */
|
||||
LoadView(GfxBase->ActiView); /* restore system view */
|
||||
FreeVPortCopLists(&vp);
|
||||
FreeCprList(view.LOFCprList);
|
||||
FreeColorMap(vp.ColorMap);
|
||||
FreeBitMap(bm);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/view.h`
|
||||
- ADCD 2.1: `InitView`, `InitVPort`, `MakeVPort`, `MrgCop`, `LoadView`
|
||||
- HRM: display construction chapter
|
||||
Loading…
Add table
Add a link
Reference in a new issue