Compare commits
2
Commits
737a297436
...
331caf417a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331caf417a | ||
|
|
f51f4e83fd |
@@ -18,3 +18,7 @@ Alternativ ohne Fenster/GPU in der Konsole: `cargo run -- --cli`
|
|||||||
|
|
||||||
Ein anderes Welt-Verzeichnis laden (Default `assets/maps/props/`):
|
Ein anderes Welt-Verzeichnis laden (Default `assets/maps/props/`):
|
||||||
`cargo run -- --maps <ordner>` (Pfad relativ zum aktuellen Verzeichnis).
|
`cargo run -- --maps <ordner>` (Pfad relativ zum aktuellen Verzeichnis).
|
||||||
|
|
||||||
|
Assets (Ink-Dialoge, Blender-Welten) baut `cargo build` bei Bedarf selbst,
|
||||||
|
sofern die Werkzeuge da sind (`inklecate` liegt bei, Blender über `$BLENDER`
|
||||||
|
oder `PATH`). Ohne sie werden die eingecheckten `.ink.json` / `.glb` benutzt.
|
||||||
|
|||||||
@@ -5,20 +5,22 @@ Start in der Konsole gemeldet (`[model]`, `[audio]`, `[tex]`, …).
|
|||||||
|
|
||||||
## 3D / Blender
|
## 3D / Blender
|
||||||
|
|
||||||
- **Format:** glTF Binary (`.glb`) nach `assets/maps/props/` — alle Dateien
|
- **Ablage:** die `.blend` in ihren Map-Ordner legen —
|
||||||
dort werden beim Start geladen (anderer Ordner: `cargo run -- --maps <dir>`).
|
`assets/maps/<map>/<name>.blend`. `cargo build` (oder
|
||||||
- **Beim Export anhaken:** „Include → Custom Properties" (sonst fehlen die
|
`./tools/build-models.sh`) exportiert sie zu `<name>.glb` daneben; von
|
||||||
Properties unten) **und** „Include → Textures" / „Data → Images"
|
Hand exportieren musst du nichts. Die Welt sind alle `.glb` unter
|
||||||
(sonst fehlen die Texturen).
|
`assets/maps/props/`; ein anderer Ordner per `cargo run -- --maps <dir>`.
|
||||||
- **Maßstab:** 1 Blender-Meter = 1 Engine-Meter. Augenhöhe 1,6 m,
|
- **Maßstab:** 1 Blender-Meter = 1 Engine-Meter. Augenhöhe 1,6 m,
|
||||||
Türen/Durchgänge ≥ 2 m hoch und ≥ 0,8 m breit denken.
|
Türen/Durchgänge ≥ 2 m hoch und ≥ 0,8 m breit denken.
|
||||||
- **Texturen:** Bild im Material als Base Color zuweisen — es wird beim
|
- **Texturen:** Bild im Material als Base Color zuweisen (PNG) — es wird
|
||||||
Export in die `.glb` eingebettet und mitgeladen (kein `assets/textures/`
|
beim Export in die `.glb` eingebettet. Damit die Datei self-contained
|
||||||
mehr). Format **PNG** (Export „Images: PNG" oder „Automatic"). Fehlt das
|
bleibt: „File → External Data → Pack Resources". Fehlt das Bild,
|
||||||
Bild, erscheint die Platzhalter-Textur.
|
erscheint die Platzhalter-Textur.
|
||||||
- **Kacheln / Skalieren:** über einen **Mapping-Node** vor dem
|
- **Kacheln / Skalieren:** über einen **Mapping-Node** vor dem
|
||||||
Image-Texture-Node (Location/Scale). Die Engine backt das
|
Image-Texture-Node (Location/Scale). Die Engine backt das
|
||||||
(`KHR_texture_transform`) beim Laden in die UVs ein.
|
(`KHR_texture_transform`) beim Laden in die UVs ein.
|
||||||
|
- **Custom Properties** (unten) kommen automatisch mit; Modifier werden
|
||||||
|
beim Export angewandt.
|
||||||
|
|
||||||
### Custom Properties auf Mesh-Objekten
|
### Custom Properties auf Mesh-Objekten
|
||||||
|
|
||||||
@@ -72,8 +74,10 @@ Start in der Konsole gemeldet (`[model]`, `[audio]`, `[tex]`, …).
|
|||||||
|
|
||||||
## Testen
|
## Testen
|
||||||
|
|
||||||
- `cargo run` — Konsole zeigt beim Start, was ankam: Objekte, Dreiecke,
|
- `cargo run` — baut geänderte `.blend` neu und zeigt beim Start, was
|
||||||
Empties und **jede Custom Property**. Fehlt eine → Export-Haken prüfen.
|
ankam: Objekte, Dreiecke, Empties und **jede Custom Property**. Fehlt
|
||||||
|
eine, sitzt sie in Blender nicht am Objekt (Object Properties → Custom
|
||||||
|
Properties), nicht am Mesh-Data.
|
||||||
- Im Spiel (Konsole = das Terminal, aus dem gestartet wurde): `noclip` zum
|
- Im Spiel (Konsole = das Terminal, aus dem gestartet wurde): `noclip` zum
|
||||||
freien Fliegen, `kv` zeigt alle Variablen, `signal <name>` feuert jedes
|
freien Fliegen, `kv` zeigt alle Variablen, `signal <name>` feuert jedes
|
||||||
Signal von Hand, `reload` lädt signals.toml neu.
|
Signal von Hand, `reload` lädt signals.toml neu.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 192 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 256 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 256 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,59 +1,82 @@
|
|||||||
//! Build-Hook: kompiliert geänderte Ink-Dialoge automatisch beim Cargo-Build.
|
//! Build-Hook: baut geänderte Assets automatisch beim Cargo-Build.
|
||||||
//!
|
//!
|
||||||
//! Reines „Wann"-Stück — das eigentliche Bauen macht `tools/build-dialogues.sh`
|
//! Reines „Wann"-Stück — das eigentliche Bauen machen die Skripte unter
|
||||||
//! (und bleibt von Hand aufrufbar). Hier melden wir Cargo nur, wann es uns
|
//! `tools/` (und bleiben von Hand aufrufbar). Hier melden wir Cargo nur, wann
|
||||||
//! erneut ausführen soll, und stoßen das Skript an.
|
//! es uns erneut ausführen soll, und stoßen die Skripte an:
|
||||||
|
//!
|
||||||
|
//! * `build-dialogues.sh` — `.ink` → `.ink.json` (inklecate)
|
||||||
|
//! * `build-models.sh` — `assets/maps/**/*.blend` → `.glb` (Blender)
|
||||||
//!
|
//!
|
||||||
//! Cargo führt build.rs ausschließlich dann erneut aus, wenn eine der unten
|
//! Cargo führt build.rs ausschließlich dann erneut aus, wenn eine der unten
|
||||||
//! via `rerun-if-changed` gemeldeten Dateien sich ändert. Unveränderte
|
//! via `rerun-if-changed` gemeldeten Dateien sich ändert. Unveränderte
|
||||||
//! Rebuilds kosten also nichts; nur nach einer `.ink`-Änderung läuft
|
//! Rebuilds kosten also nichts; nur nach einer Quell-Änderung läuft das
|
||||||
//! inklecate (inkrementell nur für die betroffene Datei).
|
//! jeweilige Werkzeug (beide Skripte bauen intern inkrementell).
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let root = env!("CARGO_MANIFEST_DIR");
|
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
let script = Path::new(root).join("tools/build-dialogues.sh");
|
|
||||||
let ink_dir = Path::new(root).join("assets/interactions");
|
|
||||||
|
|
||||||
// Wann soll Cargo build.rs erneut ausführen?
|
// --- Ink-Dialoge ------------------------------------------------------
|
||||||
println!("cargo:rerun-if-changed=tools/build-dialogues.sh");
|
println!("cargo:rerun-if-changed=tools/build-dialogues.sh");
|
||||||
println!("cargo:rerun-if-changed=tools/inklecate");
|
println!("cargo:rerun-if-changed=tools/inklecate");
|
||||||
// Verzeichnis-mtime fängt neu hinzugekommene/gelöschte .ink-Dateien.
|
// Verzeichnis-mtime fängt neu hinzugekommene/gelöschte .ink-Dateien.
|
||||||
println!("cargo:rerun-if-changed=assets/interactions");
|
println!("cargo:rerun-if-changed=assets/interactions");
|
||||||
// Inhaltsänderungen einzelner .ink-Dateien einzeln melden.
|
watch_ext(&root.join("assets/interactions"), "ink");
|
||||||
if let Ok(entries) = std::fs::read_dir(&ink_dir) {
|
run_script(&root, "tools/build-dialogues.sh", "Dialog");
|
||||||
for entry in entries.flatten() {
|
|
||||||
let p = entry.path();
|
// --- Blender-Welten -------------------------------------------------
|
||||||
if p.extension().and_then(|s| s.to_str()) == Some("ink") {
|
println!("cargo:rerun-if-changed=tools/build-models.sh");
|
||||||
println!("cargo:rerun-if-changed={}", p.display());
|
// Ordner-mtime fängt neue/gelöschte Maps; die .blend selbst einzeln.
|
||||||
}
|
// Die erzeugten .glb werden NICHT beobachtet (das Skript schreibt sie).
|
||||||
|
watch_dirs_and_ext(&root.join("assets/maps"), "blend");
|
||||||
|
run_script(&root, "tools/build-models.sh", "Modell");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Jede Datei mit Endung `ext` direkt in `dir` einzeln bei Cargo anmelden.
|
||||||
|
fn watch_ext(dir: &Path, ext: &str) {
|
||||||
|
let Ok(entries) = std::fs::read_dir(dir) else { return };
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let p = entry.path();
|
||||||
|
if p.extension().and_then(|s| s.to_str()) == Some(ext) {
|
||||||
|
println!("cargo:rerun-if-changed={}", p.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Skript ausführen. Ausgabe einsammeln, damit ein Dialog-Fehler sichtbar
|
/// Wie [`watch_ext`], aber rekursiv — und jedes Unterverzeichnis wird selbst
|
||||||
// wird (Cargo blendet Build-Script-stdout sonst aus).
|
/// beobachtet (fängt neu angelegte/entfernte Maps).
|
||||||
|
fn watch_dirs_and_ext(dir: &Path, ext: &str) {
|
||||||
|
let Ok(entries) = std::fs::read_dir(dir) else { return };
|
||||||
|
println!("cargo:rerun-if-changed={}", dir.display());
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let p = entry.path();
|
||||||
|
if p.is_dir() {
|
||||||
|
watch_dirs_and_ext(&p, ext);
|
||||||
|
} else if p.extension().and_then(|s| s.to_str()) == Some(ext) {
|
||||||
|
println!("cargo:rerun-if-changed={}", p.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ein `tools/`-Skript laufen lassen. Ausgabe einsammeln (Cargo blendet
|
||||||
|
/// Build-Script-stdout sonst aus); Fehlschlag ist fatal, ein nicht startbares
|
||||||
|
/// bash nur eine Warnung — die committeten Artefakte reichen dann.
|
||||||
|
fn run_script(root: &Path, rel: &str, label: &str) {
|
||||||
|
let script = root.join(rel);
|
||||||
match Command::new("bash").arg(&script).output() {
|
match Command::new("bash").arg(&script).output() {
|
||||||
Ok(out) if out.status.success() => { /* still bei Erfolg */ }
|
Ok(out) if out.status.success() => { /* still bei Erfolg — Detail via Hand-Aufruf */ }
|
||||||
Ok(out) => {
|
Ok(out) => {
|
||||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||||
for line in stdout.lines().chain(stderr.lines()) {
|
for line in stdout.lines().chain(stderr.lines()) {
|
||||||
println!("cargo:warning={line}");
|
println!("cargo:warning={line}");
|
||||||
}
|
}
|
||||||
panic!(
|
panic!("{label}-Build fehlgeschlagen — siehe Warnungen oben. Einzeln debuggen: ./{rel}");
|
||||||
"Dialog-Build fehlgeschlagen — siehe Warnungen oben. \
|
|
||||||
Einzeln debuggen: ./tools/build-dialogues.sh"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// bash/Skript nicht startbar (z.B. fremdes OS): den Build nicht
|
println!("cargo:warning={label}-Build übersprungen ({e}). Bei Bedarf von Hand: ./{rel}");
|
||||||
// blockieren, nur warnen — die committeten .ink.json reichen.
|
|
||||||
println!(
|
|
||||||
"cargo:warning=Dialog-Build übersprungen ({e}). \
|
|
||||||
Bei Bedarf von Hand: ./tools/build-dialogues.sh"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
Alles Inhaltliche kommt aus vier Quellen:
|
|
||||||
**Blender** (Welt),
|
|
||||||
**Ink** (Dialoge/Story),
|
|
||||||
**signals.toml** (Verdrahtung),
|
|
||||||
**Assets-Ordner** (Texturen/Sounds). Fehler in Inhalten stürzen nie ab — sie werden beim
|
|
||||||
|
|
||||||
Start in der Konsole gemeldet (`[model]`, `[audio]`, `[tex]`, …).
|
|
||||||
|
|
||||||
## 3D / Blender
|
|
||||||
|
|
||||||
- **Format:** glTF Binary (`.glb`) nach `assets/maps/props/` — alle Dateien
|
|
||||||
dort werden beim Start geladen.
|
|
||||||
- **Beim Export anhaken:** „Include → Custom Properties" (sonst fehlen die
|
|
||||||
Properties unten) **und** „Include → Textures" (sonst fehlen die Texturen).
|
|
||||||
- **Maßstab:** 1 Blender-Meter = 1 Engine-Meter. Augenhöhe 1,6 m,
|
|
||||||
Türen/Durchgänge ≥ 2 m hoch und ≥ 0,8 m breit denken.
|
|
||||||
- **Texturen:** Bild im Material als Base Color zuweisen — wird beim Export
|
|
||||||
in die `.glb` eingebettet (PNG), kein `assets/textures/` mehr. Fehlt das
|
|
||||||
Bild, erscheint die Platzhalter-Textur. Kacheln/Skalieren über einen
|
|
||||||
Mapping-Node (`KHR_texture_transform` wird beim Laden in die UVs gebacken).
|
|
||||||
|
|
||||||
### Custom Properties auf Mesh-Objekten
|
|
||||||
|
|
||||||
| Property | Wirkung |
|
|
||||||
|---|---|
|
|
||||||
| *(keine)* | nur sichtbar, kein Anfassen |
|
|
||||||
| `collide = 1` | sichtbar **und** solide (Spieler kollidiert mit der konvexen Hülle des Meshes — Dellen/Löcher werden überspannt) |
|
|
||||||
| `collide = proxy` | unsichtbares Kollisionsvolumen (für Fein-Collider neben Sichtgeometrie) |
|
|
||||||
| `signal = <name>` **mit** collide | Klick-Ziel: Anklicken feuert das Signal `<name>` |
|
|
||||||
| `signal = <name>` **ohne** collide | unsichtbare Trigger-Zone: Betreten feuert `<name>` einmal (erneut erst nach Verlassen; „nur einmal überhaupt" selbst per KV-Flag bauen) |
|
|
||||||
|
|
||||||
- `collide = 0` schaltet ab, ohne die Property zu löschen.
|
|
||||||
- Objektname ist der Interact-Key: Blender-Suffixe (`Ding.001`) werden beim
|
|
||||||
Signal-Lookup automatisch gestrippt — `[Ding]` in signals.toml trifft alle.
|
|
||||||
|
|
||||||
### Custom Properties auf Empties
|
|
||||||
|
|
||||||
| Property | Wirkung |
|
|
||||||
|---|---|
|
|
||||||
| `role = spawn` | Spieler-Startpunkt (Fußpunkt = Empty-Position) |
|
|
||||||
| `sound = <name>` | Ambient-Loop `assets/sounds/<name>.wav` an dieser Position |
|
|
||||||
| `radius = <m>` | Hörradius des Sounds (linear leiser bis Stille; Default 8) |
|
|
||||||
|
|
||||||
## Audio
|
|
||||||
|
|
||||||
- **Format:** WAV, **mono, 16 bit, 44100 Hz** — nichts anderes. Ablage in
|
|
||||||
`assets/sounds/`, angesprochen ohne Endung (`pickup` → `pickup.wav`).
|
|
||||||
- **Ambient:** per Empty (siehe oben), loopt immer — Loop-Punkt sauber schneiden.
|
|
||||||
- **Einmal-SFX:** per Action `play_sound <name>` (aus signals.toml oder Ink-Tag).
|
|
||||||
|
|
||||||
## Dialoge / Ink
|
|
||||||
|
|
||||||
- `.ink` nach `assets/interactions/` — wird beim Build automatisch
|
|
||||||
kompiliert (bei Bedarf von Hand: `./tools/build-dialogues.sh`).
|
|
||||||
- Gestartet per Action `start_ink <datei>.ink.json`.
|
|
||||||
- **Variablen:** alle Ink-`VAR` landen automatisch im Spiel-KV und synchen
|
|
||||||
in beide Richtungen — `_`-Prefix (`VAR _tmp = 0`) bleibt Ink-lokal.
|
|
||||||
- **Tags feuern Actions:** `# set has_key true`, `# play_sound klick`,
|
|
||||||
`# mode play` … (gleiche Verben wie signals.toml). Unbekannte Tags sind
|
|
||||||
erlaubt (reine Metadaten).
|
|
||||||
|
|
||||||
## signals.toml (`assets/signals.toml`)
|
|
||||||
|
|
||||||
- Verdrahtet Signal → Aktionen. Signal-Namen: Objektname (Klick), Wert der
|
|
||||||
`signal`-Property (Zonen/Klick-Ziele), oder frei (aus Ink).
|
|
||||||
- Verben: `start_ink`, `set`, `inc`, `clear`, `debug_log`, `play_sound`,
|
|
||||||
`mode play|free|menu`.
|
|
||||||
- `$self` = auslösender Objektname (für generische Einträge wie
|
|
||||||
`set $self true`).
|
|
||||||
- `[init]` feuert einmal beim Start — Ort für KV-Defaults.
|
|
||||||
|
|
||||||
## Testen
|
|
||||||
|
|
||||||
- `cargo run` — Konsole zeigt beim Start, was ankam: Objekte, Dreiecke,
|
|
||||||
Empties und **jede Custom Property**. Fehlt eine → Export-Haken prüfen.
|
|
||||||
- Im Spiel (Konsole = das Terminal, aus dem gestartet wurde): `noclip` zum
|
|
||||||
freien Fliegen, `kv` zeigt alle Variablen, `signal <name>` feuert jedes
|
|
||||||
Signal von Hand, `reload` lädt signals.toml neu.
|
|
||||||
@@ -27,3 +27,29 @@ Das Skript sucht den Ink-Compiler in dieser Reihenfolge:
|
|||||||
1. `$INKLECATE` (Pfad zum Binary)
|
1. `$INKLECATE` (Pfad zum Binary)
|
||||||
2. `tools/inklecate` (mitgeliefert)
|
2. `tools/inklecate` (mitgeliefert)
|
||||||
3. `inklecate` im `PATH`
|
3. `inklecate` im `PATH`
|
||||||
|
|
||||||
|
## build-models.sh
|
||||||
|
|
||||||
|
Exportiert die Blender-Welten zu den `.glb`, die das Spiel lädt.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./tools/build-models.sh # nur Geändertes neu bauen
|
||||||
|
./tools/build-models.sh -f # alles neu bauen
|
||||||
|
```
|
||||||
|
|
||||||
|
Workflow für die Autorin: `.blend` in den jeweiligen Map-Ordner legen —
|
||||||
|
`assets/maps/<map>/<name>.blend` — Skript laufen lassen, fertig. Die
|
||||||
|
`.glb` landen direkt daneben (`assets/maps/<map>/<name>.glb`) und werden
|
||||||
|
mit ins Repo eingecheckt, damit ein frischer Clone ohne Blender spielbar
|
||||||
|
ist. Ein `.glb` ohne `.blend` daneben (z.B. `props/testscene.glb`) bleibt
|
||||||
|
unangetastet.
|
||||||
|
|
||||||
|
**Automatisch beim Build:** `cargo build`/`cargo run` ruft dieses Skript
|
||||||
|
über `build.rs` selbst auf, sobald sich eine `.blend` geändert hat.
|
||||||
|
|
||||||
|
Blender wird über `$BLENDER` oder den `PATH` gefunden. Fehlt es, wird der
|
||||||
|
Schritt übersprungen (kein Fehler — die committeten `.glb` reichen).
|
||||||
|
Bundeln geht nicht, dafür ist Blender zu groß.
|
||||||
|
|
||||||
|
Tipp: in Blender „File → External Data → Pack Resources", dann liegen die
|
||||||
|
Texturen in der `.blend` und der Export ist self-contained.
|
||||||
|
|||||||
Executable
+86
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Exportiert alle Blender-Welten unter assets/maps/ zu den .glb, die das
|
||||||
|
# Spiel lädt.
|
||||||
|
#
|
||||||
|
# Für die Autorin: Leg deine .blend in den jeweiligen Map-Ordner
|
||||||
|
# assets/maps/<map>/<name>.blend
|
||||||
|
# und führ danach dieses Skript aus:
|
||||||
|
# ./tools/build-models.sh
|
||||||
|
# Fertig — die .glb landen direkt daneben (assets/maps/<map>/<name>.glb).
|
||||||
|
#
|
||||||
|
# Standardmäßig wird nur exportiert, was sich seit dem letzten Mal geändert
|
||||||
|
# hat. Mit -f / --force wird alles neu gebaut.
|
||||||
|
#
|
||||||
|
# Tipp: in Blender „File -> External Data -> Pack Resources", dann sind die
|
||||||
|
# Texturen in der .blend und der Export ist self-contained.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Repo-Wurzel relativ zum Skript bestimmen — egal, von wo aufgerufen.
|
||||||
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
root="$(cd "$script_dir/.." && pwd)"
|
||||||
|
maps_dir="$root/assets/maps"
|
||||||
|
|
||||||
|
force=0
|
||||||
|
case "${1:-}" in
|
||||||
|
-f|--force) force=1 ;;
|
||||||
|
"") ;;
|
||||||
|
*) echo "Unbekannte Option: $1 (nur -f/--force)" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# blender finden: $BLENDER -> PATH. Bundeln geht nicht (zu groß) — fehlt es,
|
||||||
|
# ist das kein Fehler: die committeten .glb reichen zum Bauen und Spielen.
|
||||||
|
if [ -n "${BLENDER:-}" ] && [ -x "$BLENDER" ]; then
|
||||||
|
blender="$BLENDER"
|
||||||
|
elif command -v blender >/dev/null 2>&1; then
|
||||||
|
blender="$(command -v blender)"
|
||||||
|
else
|
||||||
|
echo " übersprungen blender nicht gefunden (\$BLENDER oder PATH) — .glb bleiben wie committet" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$maps_dir" ]; then
|
||||||
|
echo "Kein Map-Ordner: $maps_dir" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Der Export als Python-Einzeiler. filepath ohne Endung — export_format='GLB'
|
||||||
|
# hängt .glb an. export_extras trägt collide/signal/role mit.
|
||||||
|
gltf_expr='
|
||||||
|
import bpy, sys
|
||||||
|
out = sys.argv[-1]
|
||||||
|
bpy.ops.export_scene.gltf(
|
||||||
|
filepath=out,
|
||||||
|
export_format="GLB",
|
||||||
|
export_extras=True,
|
||||||
|
export_yup=True,
|
||||||
|
export_apply=True,
|
||||||
|
export_image_format="AUTO",
|
||||||
|
)'
|
||||||
|
|
||||||
|
built=0 skipped=0 failed=0
|
||||||
|
while IFS= read -r -d '' src; do
|
||||||
|
out="${src%.blend}.glb"
|
||||||
|
rel="${src#"$root"/}"
|
||||||
|
|
||||||
|
# Inkrementell: überspringen, wenn .glb existiert und neuer ist.
|
||||||
|
if [ "$force" -eq 0 ] && [ -f "$out" ] && [ "$out" -nt "$src" ]; then
|
||||||
|
printf ' aktuell %s\n' "$rel"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if log="$("$blender" -b --factory-startup "$src" \
|
||||||
|
--python-expr "$gltf_expr" -- "${out%.glb}" 2>&1)"; then
|
||||||
|
printf ' gebaut %s\n' "$rel"
|
||||||
|
built=$((built + 1))
|
||||||
|
else
|
||||||
|
printf ' FEHLER %s\n' "$rel"
|
||||||
|
printf '%s\n' "$log" | sed 's/^/ /'
|
||||||
|
failed=$((failed + 1))
|
||||||
|
fi
|
||||||
|
done < <(find "$maps_dir" -type f -name '*.blend' -print0 | sort -z)
|
||||||
|
|
||||||
|
echo "—— $built gebaut, $skipped aktuell, $failed fehlgeschlagen ——"
|
||||||
|
[ "$failed" -eq 0 ]
|
||||||
Reference in New Issue
Block a user