Renderovací pipeline
TUIX renderuje terminálové UI přes vícestupňový pipeline: výpočet geometrie, tvorbu obsahu, kompozici a delta renderování. Všechny fáze běží v C pro maximální výkon.
Fáze pipeline
- Výpočet geometrie — vynásobit proporční modifikátory rozměry terminálu
- Tvorba obsahu — build_content každého widgetu vytváří pixelový buffer
- Kompozice — vrstvení bufferů scén do finálního framebufferu (pořadí malíře)
- Delta renderování — hashování řádků, přeskočení nezměněných, výstup pouze změněného ANSI
Výpočet geometrie
Před tvorbou obsahu přepočítá resolver geometrie plovoucí modifikátory widgetů na absolutní souřadnice podle aktuální velikosti terminálu. Ve v0.3 se buffery s platným parent_uid řeší relativně vůči rodičovskému bufferu, což umožňuje parent/child layouty.
buffer.width = terminal_width × width_mod
buffer.height = terminal_height × height_mod
buffer.margin_left = terminal_width × margin_left_mod
buffer.margin_top = terminal_height × margin_top_modPokud sestavovač widgetu definuje callback on_resize, zavolá se po výpočtu geometrie s novou šířkou a výškou.
Model pixelu
Každá buňka v bufferu je TuixPixel obsahující: 8bajtový UTF-8 symbol, RGB barvy popředí a pozadí, stylové příznaky (tučné, kurzíva, podtržení, ztlumení) a pole cache kvantizace.
| Pole | Velikost | Popis |
|---|---|---|
| sym | 8 bytes | UTF-8 znak (vyplněný nulovými bajty) |
| styles.fg | 3 bytes | RGB popředí (0–255 na kanál) |
| styles.bg | 3 bytes | RGB pozadí (0–255 na kanál) |
| styles.bold | 1 byte | Příznak tučného textu |
| styles.italic | 1 byte | Příznak kurzívy |
| styles.underlined | 1 byte | Příznak podtržení |
| styles.dim | 1 byte | Příznak ztlumeného textu |
| q_fg, q_bg | 6 bytes | Cache kvantizovaných barev (RGB565) |
| q_cached | 1 byte | Zda je kvantizační cache platná |
Kompozice
Kompozitor alokuje finální framebuffer o velikosti terminal_width × (terminal_height - 1). Spodní řádek je rezervovaný pro log výstup. Ve v0.3 kompozice používá traversal-chain vrstvení: root buffery se řadí podle z-index a každý parent/child podstrom se projde před vykreslením, aby se zachovalo hierarchické vrstvení.
Delta renderování
Renderer porovnává aktuální snímek s předchozím, aby přeskočil nezměněný obsah:
- Hashovat každý řádek pomocí FNV-1a nad surovými (nekvantizovanými) daty pixelů
- Porovnat s hashi řádků z předchozího snímku
- Zpracovat pouze řádky se změněným hashem
- Pro změněné řádky kvantizovat barvy (RGB → RGB565 pomocí předpočítané 128KB LUT)
- Seskupit sousední pixely se stejným stylem do jedné SGR escape sekvence
- Vysílat nastavení kurzoru (\e[Y;XH) jen když je potřeba (přeskočit pro sekvenční buňky)
- Streamovat výstup po 256KB blocích
Režimy barevného výstupu
LUT pro kvantizaci barev mapuje hodnoty RGB565 na nejbližší dostupnou terminálovou barvu. Automaticky se používají tři režimy podle nejlepší shody:
| Režim | Formát | Barvy |
|---|---|---|
| ANSI16 | \e[30-37m / \e[90-97m | 16 základních terminálových barev |
| ANSI256 | \e[38;5;Nm | Paleta 256 barev |
| Truecolor | \e[38;2;R;G;Bm | Plné 24-bit RGB (16,7 M barev) |
Halfblock renderování (volitelný modul)
Zdrojová distribuce obsahuje halfblock renderer (rendering_halfblocks.c), který používá znak Unicode horního půlbloku (▀ U+2580) pro dosažení 2× vertikálního rozlišení. Dva řádky pixelů jsou zabaleny do jednoho terminálového řádku tak, že se barva popředí použije pro horní polovinu a barva pozadí pro dolní polovinu.
Instrumentace a kompaktace scén
v0.3 přidává instrumentaci aktivity scén a konzervativní API pro kompaktaci. Místo eager globální cache je doporučená strategie data-first: číst statistiky scén a kompaktovat studené scény při splnění prahů.
from tuix.core import scenes
stats = scenes.get_scene_stats(b"main")
freed = scenes.compact_scene_pixels(b"main")
compacted = scenes.compact_cold_scenes(120, 64 * 1024, keep_active_scene=True)Zpracování změny velikosti
Rozměry terminálu se čtou v každém snímku pomocí API specifických pro platformu (ReadConsoleScreenBufferInfo na Windows, ioctl TIOCGWINSZ na POSIX). Při detekci změny velikosti kompozitor realokuje svůj statický finální buffer, přepočítají se geometrie všech widgetů a spustí se kompletní překreslení.