***************************
* Raspberry Pi Beamertool *
***************************
Original von Moritz <mo@blog-srv.net>, portiert auf Raspberry Pi 4 /
Raspberry Pi OS Lite (64bit) bzw. Debian 13 "trixie".

--------------------------------
Architektur: mpv als alleiniger Anzeigepfad
--------------------------------
Das Original nutzte den alten Broadcom-"Legacy"-Grafikstack
(bcm_host/Dispmanx/EGL, OpenGL ES 1.1 Fixed-Function, OpenMAX IL/ilclient),
der auf dem Pi 4/Debian 13 nicht mehr existiert. Der erste Portierungs-
Ansatz (SDL2 mit dem "kmsdrm"-Videotreiber, direkt auf den Bildschirm
gezeichnet) erwies sich in der Praxis auf manchen Pi4/Debian-13-
Kombinationen als unzuverlässig - trotz erkanntem Monitor blieb der
Bildschirm mitunter schwarz, ohne dass ein Fehler geloggt wurde.

Die jetzige Architektur nutzt daher denselben Ansatz wie das parallel
entwickelte Python-Schwesterprojekt (rpi-beamertool v3, Pi Zero 2 W):
EINE dauerhaft laufende **mpv-Instanz ist der alleinige Anzeigepfad**.
mpv's eigener GPU/DRM-Renderpfad hat sich als deutlich robuster erwiesen.

 - Unser Programm zeichnet die Laser-Simulation komplett UNSICHTBAR im
   Hintergrund (EGL "surfaceless"-Kontext über /dev/dri/renderD128 - kein
   Bildschirm, kein Connector, keine Monitor-Erkennung nötig) und schickt
   die fertigen Frames als Rohvideo-Strom über eine benannte Pipe (FIFO)
   an mpv (Demuxer "rawvideo").
 - Der Media Player (Fotos/Videos aus ./media/) schaltet mpv per IPC-
   Kommando ("loadfile") stattdessen direkt auf die gewählte Datei um -
   mpv decodiert selbst, unser Programm muss dafür nichts mehr rendern.
 - Umschalten zwischen beiden Modi passiert nahtlos durch ein erneutes
   "loadfile" per IPC.

Das ist deutlich robuster, hat aber eine Konsequenz: Video-**Gobos**
innerhalb der Laser-Simulation (Textur-Dateien wie z.B. 194.h264) werden
aktuell NICHT dekodiert (ein zweiter Video-Decoder-Prozess würde mit dem
alleinigen mpv kollidieren) - sie zeigen einen blauen Platzhalter. Das
Kernfeature (DMX-gesteuerte Gobos/Muster als PNG/GIF) sowie der komplette
Media Player sind davon nicht betroffen.

Weitere Änderungen:
 - Autostart über systemd (rpi-beamertool.service) statt /etc/rc.local
 - Installer nutzt apt statt aptitude und baut aus dem Quellcode
 - Konfigurierbare Streaming-Auflösung/Framerate (config.txt:
   RENDER_WIDTH/RENDER_HEIGHT/RENDER_FPS, Standard 960x540@25fps -
   Kompromiss aus Bildschärfe und CPU-/Pipe-Last auf dem Pi4)

Unverändert/portabel geblieben: Art-Net-Empfang, ncurses-Konsole,
Canvas-/Zoom-/Rotationslogik, GIF-/PNG-Loader (für die normalen
Bild-Gobos), das PHP-Webinterface (tools/index.php).

-----------------------------
Media Player
-----------------------------
Zusätzlich zur Laser-Simulation gibt es einen Media Player, der Fotos/
Videos aus dem Verzeichnis /opt/rpi-beamertool/media/ abspielt (mpv spielt
sie direkt ab - Formate: alles was mpv kann, u.a. png/jpg/jpeg/bmp/gif/
mp4/mkv/mov/avi/webm). Er wird über einen eigenen, vom Laser-Kanalblock
unabhängigen Art-Net-Kanal gesteuert (config.txt: MEDIA_PLAYER_CHANNEL,
Kanal RELATIV zu DMX_START, z.B. bedeutet 40 bei DMX_START=100 den
absoluten Art-Net-Kanal 140):

 - Wert 0: normale Laser-Simulation (Standard)
 - Wert 1-255: Media Player aktiv, der Wert wählt die Datei aus dem
   alphabetisch sortierten Verzeichnisinhalt (in Einerschritten, mit
   Wraparound falls weniger Dateien vorhanden sind als DMX-Werte)

Passende DMXControl-3-Geräteprofile (DDFs) mit fertig eingerichtetem
Media-Player-Kanal liegen unter resources/ddf/ (siehe dortiges README für
Details und Pflege-Werkzeuge tools/genprefix.sh, tools/genddflist.sh).

-----------------------------
Nebel/Haze & Laser-Tunnel (Festival-Look)
-----------------------------
Zusätzlich zur reinen Gobo-Simulation gibt es zwei weitere, unabhängige
Effekte, die zusammen den Eindruck einer echten Festival-Lasershow mit
Nebelmaschine erzeugen:

 - Nebeldichte (config.txt: FOG_DENSITY_CHANNEL): ein bildschirmfüllender,
   kachelbarer Dunstschleier aus einer einmalig prozedural generierten,
   realistisch wirkenden Wolkentextur (resources/textures/fog.png), die sich
   langsam und leicht diagonal verschiebt (wie von Luft bewegter Nebel).
 - Laserstrahl-Sichtbarkeit (config.txt: BEAM_VISIBILITY_CHANNEL): zeigt
   zusätzlich zum scharfen Gobo im Vordergrund einen "Tunnel", der die
   FORM des aktuellen Gobos (z.B. ein Dreieck) mehrfach verkleinert zu
   einem festen, gemeinsamen Fluchtpunkt (Bühne/Tiefe, Bildmitte) hin
   abbildet - unabhängig von der Gobo-Position, so wie bei einem echten
   Laser mit festem Standort. Der Tunnel wird zusätzlich dort heller
   dargestellt, wo er auf eine lokal hellere/dichtere Nebelstelle trifft
   (eigener Shader sampelt Gobo- UND Nebeltextur gemeinsam).

Wichtig: Der Tunnel ist nur sichtbar, wenn BEIDE Kanäle aktiv sind UND das
Gobo selbst eine Helligkeit (Dimmer) über 0 hat - die Gesamthelligkeit des
Tunnels ergibt sich aus Dimmer × Laserstrahl-Sichtbarkeit × Nebeldichte.
Bei Nebeldichte=0 verschwindet der Tunnel komplett, es bleibt nur das
normale, scharfe Gobo im Vordergrund sichtbar (Dimmer-Steuerung
unverändert wie bisher).

Beide Kanäle sind wie MEDIA_PLAYER_CHANNEL relativ zu DMX_START und
0-255 linear auf 0-100% abgebildet. Auskommentiert/-1 = Effekt aus
(Standard). Die passenden Regler liegen in den DDFs (resources/ddf/) im
selben, letzten Kanalblock wie die Laser-Simulation/Media-Player-
Umschaltung.

-----------------------------
Kachel-Effekt (Kaleidoskop-Look)
-----------------------------
Statt des Bildes 1:1 kann es stattdessen gekachelt dargestellt werden -
ein NxN-Raster, in dem jede Kachel das komplette Bild zeigt (nicht einen
Ausschnitt davon). Zwei config.txt-Kanäle (wie üblich relativ zu
DMX_START, Wertebereiche als Schalter statt linearer Regler):

 - TILE_COUNT_CHANNEL: 0-63=aus, 64-127=4 Kacheln (2x2), 128-191=16
   Kacheln (4x4), 192-255=64 Kacheln (8x8)
 - TILE_MIRROR_CHANNEL: 0-84=1:1 (jede Kachel identisch), 85-169=vertikal
   gespiegelt, 170-255=horizontal gespiegelt

Bei "vertikal gespiegelt" zeigt die obere Rasterhälfte das Bild normal,
die untere Hälfte auf dem Kopf (Spiegelsymmetrie an der waagerechten
Mitte - wie eine Wasserspiegelung). "Horizontal gespiegelt" funktioniert
analog an der senkrechten Mitte: linke Hälfte normal, rechte Hälfte
seitenverkehrt.

Technisch: die fertig gerenderte Szene wird in einem zweiten Rendering-
Durchgang (eigenes FBO) NxN-fach mit passender UV-Spiegelung pro Kachel
neu zusammengesetzt - kein zusätzlicher Shader nötig, der bestehende
Gobo-Textur-Shader wird wiederverwendet.

-----------------------------
Farbverlauf-Raster-Effekt (Kaleidoskop-Hintergrund)
-----------------------------
Ganz im Hintergrund (hinter Nebel, Laser-Tunnel und Gobos) kann ein
diagonaler Farbverlauf langsam durchlaufen, sichtbar durch ein
Kachel-Raster mit leicht "atmenden" Lücken hindurch (jede Rasterzelle
"pulsiert" unabhängig langsam in der Lückenbreite).

 - GRADIENT_INTENSITY_CHANNEL: Sichtbarkeit, 0-255 linear -> 0-100%
 - GRADIENT_START_R/G/B_CHANNEL und GRADIENT_END_R/G/B_CHANNEL: Anfangs-
   und Endfarbe des Verlaufs (je 3 Kanäle, direkt 0-255) - in den DDFs als
   ein einziges <matrix dmxchannel="..." rows="2" columns="1"/>-Element
   ausgeführt (alle 6 Kanäle implizit ab der Startadresse), damit
   DMXControl echte Farbpicker zeigt und seine Effekte darauf anwenden kann
 - GRADIENT_SPEED_CHANNEL: Durchlaufgeschwindigkeit, 0-255 linear
 - GRADIENT_MODE_CHANNEL: Schalter - 0-127 = zwei Farben (Start/Ende
   pendeln als Dreieckswelle hin und her), 128-255 = Regenbogen (volles
   Farbspektrum, Start-/Endfarbe dann ungenutzt)

Alle relativ zu DMX_START, wie die übrigen "nackten" Kanäle. Details und
die genauen Kanalnummern je DDF-Layer-Anzahl: resources/ddf/README.

-----------------------------
Laserstrahl-Fächer
-----------------------------
Zusätzlich zum normalen Gobo kann pro Laser-Layer ein Fächer aus dünnen,
geraden Strahlen eingeschaltet werden, die radial von der Layer-Position
aus über den Bildschirmrand hinausragen - wie ein echter Laserprojektor,
der irgendwo im Raum steht. Nutzt die vier Kanäle, die pro 20-Kanal-
Layer-Block sonst frei geblieben wären (siehe DMX-Kanallayout weiter
oben): +13 Sichtbarkeit, +17 Anzahl Strahlen (2-64), +18 Länge, +19
Breite. Ursprung = Layer-Position (+2/+3), Richtung = normale
Layer-Rotation (+6/+15, derselbe "2D-Effekt", der auch das Gobo dreht),
Farbe = bestehender Farbkanal (+10/+11/+12), Helligkeit = Sichtbarkeit ×
Dimmer (+1), unsichtbar bei geschlossenem Shutter (+14). Additiv
gemischt - sich kreuzende Strahlen hellen sich gegenseitig auf.

-----------------------------
Weitere Einstellungen (config.txt)
-----------------------------
 - TUNNEL_STEPS: Anzahl der verkleinerten Gobo-"Echo"-Kopien im Laser-
   Tunnel-Effekt (Standard 10). Mehr Schritte = dichterer/glatterer
   Tunnel, aber mehr Rechenlast pro Frame.
 - ARTNET_DEBUG=1: loggt jedes empfangene und geaenderte Art-Net-Signal
   (Universe/Kanal/Wert) - hilft zu pruefen, ob Pakete korrekt ankommen
   und zum richtigen Universe/Subnet passen. Nur zum Debuggen einschalten
   (journalctl -u rpi-beamertool -f), erzeugt bei aktivem Sender viele
   Logzeilen.
 - RECORD_VIDEO=1 + RECORD_VIDEO_PATH: zeichnet die Laser-Simulation
   zusaetzlich als MP4-Datei auf (z.B. fuer Demo-Zwecke), per ffmpeg im
   Hintergrund. Waehrend der Media Player aktiv ist, pausiert die
   Aufzeichnung automatisch (unser Renderer liefert dann keine Frames).

-----------------------------
Installation
-----------------------------
Getestet mit Raspberry Pi OS Lite (64bit, Bookworm/Trixie) und Debian 13
"trixie" auf einem Raspberry Pi 4.

Automatisch (empfohlen):

    sudo ./tools/rpi-bt-install.sh

Das Skript installiert die Build-Abhängigkeiten, baut das Programm, kopiert
alles nach /opt/rpi-beamertool und richtet den systemd-Autostart ein.

Manuell:

    sudo apt-get update
    sudo apt-get install build-essential cmake pkg-config \
        libegl1-mesa-dev libgles2-mesa-dev libncurses-dev mpv ffmpeg

    mkdir build && cd build
    cmake ..
    make -j$(nproc)
    ./rpi-beamertool

-----------------------------
Bedienung / Deinstallation
-----------------------------
    systemctl start rpi-beamertool      # bzw. tools/rpi-bt-start.sh
    systemctl restart rpi-beamertool    # bzw. tools/rpi-bt-restart.sh
    journalctl -u rpi-beamertool -f     # Logs
    sudo ./tools/rpi-bt-uninstall.sh    # deinstallieren

-----------------------------
Versionierung & weitere Doku
-----------------------------
    ./version.sh patch    # bzw. minor/major - vor dem Bauen ausfuehren
    ./version.sh show     # aktuelle Version anzeigen

Schreibt src/version.h (einzige Versionsquelle, wird einkompiliert) und
stempelt config.txt, die systemd-Unit sowie alle DDF-Dateien mit
Versionsnummer + Zeitstempel. Ausfuehrliches Handbuch: docs/manual.md

-----
INFO:
-----
 - Braucht einen angeschlossenen, erkannten Monitor (mpv zeigt sonst
   naturgemäß nichts an), aber KEINEN eigenen Bildschirmzugriff für unser
   Programm selbst mehr - dadurch auch kein TTY/VT-Gerangel mehr wie bei
   der direkten kmsdrm-Variante.
 - Der ausführende Nutzer muss in den Gruppen "video" und "render" sein
   (macht der Installer automatisch); nach dem ersten Hinzufügen ggf.
   einmal neu einloggen/rebooten.
 - Bei Rucklern in der Laser-Simulation zuerst RENDER_WIDTH/RENDER_HEIGHT/
   RENDER_FPS in config.txt reduzieren.
 - Video-Gobos (Textur-Dateien wie z.B. 194.h264) werden aktuell nicht
   dekodiert (blauer Platzhalter, siehe oben) - PNG/GIF-Gobos sind davon
   nicht betroffen.
 - Die Berechnung der automatischen Drehungen und des Shutters erfolgt pro
   Frame (wie im Original/Windows-Beamertool). Besser wäre eine
   Berechnung pro Zeit, da die Framerate bei vielen großen Gobos absinken
   kann.
 - Der Animationsregler ist wirkungslos, das Steuern von GIF-Animationen
   ist (noch) nicht implementiert.
 - Man kann wählen, ob sich die Zoomfunktion wie im Original verhält oder
   in einen Kreis zoomt.
