003 - Rendering System
Das Unified Rendering System ermöglicht renderer-agnostischen Code.
Das Problem
Stell dir vor: Du hast ein wunderschönes Artwork programmiert mit Canvas2D. Jetzt willst du:
- Mehr Performance – Tausende Partikel ruckeln, WebGL wäre besser
- SVG exportieren – Für deinen Pen-Plotter
- Verschiedene Ausgaben – Live auf dem Bildschirm UND als Vektor-Datei
Ohne Abstraktion müsstest du deinen Code dreimal schreiben. Mit dem Unified Rendering System schreibst du ihn einmal.
Die Lösung
Das RenderContext ist eine Facade – eine einheitliche Schnittstelle, hinter der verschiedene Renderer stecken. Dein Code ruft ctx.drawCircle() auf, und je nach aktivem Renderer landet das auf Canvas2D, WebGL oder in einer SVG-Datei.
Warum Facade? Du willst dich nicht um Implementierungsdetails kümmern. Ein Kreis ist ein Kreis, egal ob er mit arc() (Canvas2D), Shader-Triangles (WebGL) oder <circle> (SVG) gezeichnet wird.
Architektur
┌─────────────────────────────────────────────────────────────┐
│ Artwork Code │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Brush/Agent Code │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Facade │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ RenderContext │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Renderer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Canvas2D- │ │ WebGL- │ │ SVG- │ │
│ │ Renderer │ │ Renderer │ │ Renderer │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘Komponenten
| Klasse | Datei | Funktion |
|---|---|---|
IRenderer |
IRenderer.ts |
Interface für alle Renderer |
RenderContext |
RenderContext.ts |
Facade, wählt aktiven Renderer |
Canvas2DRenderer |
Canvas2DRenderer.ts |
Standard Canvas 2D |
WebGLRenderer |
WebGLRenderer.ts |
GPU-beschleunigt |
SVGRenderer |
SVGRenderer.ts |
Vektor-Export |
RenderContext
Die Haupt-Facade für das Rendering.
Factory-Funktionen:
| Funktion | Beschreibung |
|---|---|
createCanvas2DContext(canvas) |
Canvas 2D Renderer |
createWebGLContext(canvas) |
WebGL Renderer |
createSVGContext(width, height) |
SVG Renderer |
createAutoContext(canvas) |
Auto-Detect |
Renderer wechseln:
const ctx = createAutoContext(canvas);
ctx.setRenderer('webgl'); // oder 'canvas2d', 'svg'IRenderer Interface
Alle Renderer implementieren dieses Interface.
Primitive-Methoden:
| Methode | Beschreibung |
|---|---|
drawCircle(x, y, r, style) |
Kreis |
drawRect(x, y, w, h, style) |
Rechteck |
drawLine(x1, y1, x2, y2, style) |
Linie |
drawPolygon(points, style) |
Polygon |
drawPath(commands, style) |
SVG-artiger Pfad |
drawEllipse(x, y, rx, ry, style) |
Ellipse |
State-Methoden:
| Methode | Beschreibung |
|---|---|
save() |
State auf Stack |
restore() |
State von Stack |
translate(x, y) |
Verschieben |
rotate(angle) |
Rotieren (Radians) |
scale(sx, sy) |
Skalieren |
setTransform(matrix) |
Matrix setzen |
Utility-Methoden:
| Methode | Beschreibung |
|---|---|
clear(color?) |
Canvas löschen |
resize(w, h) |
Größe ändern |
getImageData() |
Pixel lesen |
PrimitiveStyle
Styling für alle Primitives.
| Property | Typ | Beschreibung |
|---|---|---|
fill |
RenderColor |
Füllfarbe |
stroke |
RenderColor |
Rahmenfarbe |
strokeWidth |
number |
Rahmenbreite |
lineCap |
'butt' | 'round' | 'square' |
Linienenden |
lineJoin |
'miter' | 'round' | 'bevel' |
Linienecken |
opacity |
number |
Transparenz (0-1) |
RenderColor
Farben können in verschiedenen Formaten angegeben werden:
type RenderColor =
| string // '#FF0000', 'red', 'rgb(255,0,0)'
| { r, g, b, a? } // Objekt
| [r, g, b, a?] // ArrayUtility-Funktionen:
| Funktion | Beschreibung |
|---|---|
parseColor(input) |
Zu {r,g,b,a} |
colorToHex(color) |
Zu #RRGGBB |
colorToRgba(color) |
Zu rgba(...) |
Canvas2DRenderer
Standard-Renderer für die meisten Anwendungsfälle.
Vorteile:
- Breiteste Browser-Unterstützung
- Einfaches Debugging
- Gute Performance für 2D
Limitierungen:
- Kein GPU-Beschleunigung für komplexe Effekte
- Langsamer bei vielen Partikeln
WebGLRenderer
GPU-beschleunigtes Rendering.
Vorteile:
- Hohe Performance bei vielen Objekten
- 60fps auch bei Tausenden Partikeln
- Shader-Effekte möglich
Limitierungen:
- Komplexere Implementierung
- Nicht alle Primitives gleich effizient
SVGRenderer
Für Vektor-Export (z.B. Pen-Plotter).
Vorteile:
- Verlustfreie Skalierung
- Perfekt für Plotter-Export
- Layer-Unterstützung
Besonderheiten:
- Kein Realtime-Rendering
- Sammelt Primitive für Export
- Layer per
svgLayerName
Export:
const svgCtx = createSVGContext(1000, 1000);
// ... zeichnen ...
const svgString = svgCtx.toSVGString();Transform2D
Transformations-Matrix.
interface Transform2D {
a: number; // scale x
b: number; // skew y
c: number; // skew x
d: number; // scale y
e: number; // translate x
f: number; // translate y
}Helper:
| Funktion | Beschreibung |
|---|---|
identityTransform() |
Einheitsmatrix |
createTransform(opts) |
Aus translate/rotate/scale |
Brush → Style Konvertierung
import { brushToStyle } from '@carstennichte/cc-toolbox';
const style = brushToStyle(brush);
// → { fill, stroke, strokeWidth, ... }