first commit
This commit is contained in:
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# render.sh — turn a CADAM benchmark .scad into an orbiting GIF (and an optional
|
||||
# multi-view contact sheet for inspection). Mirrors how CADAM previews models in
|
||||
# the browser: BOSL2/MCAD on the library path, color() parts preserved, a clean
|
||||
# orbit around the vertical axis.
|
||||
#
|
||||
# Usage:
|
||||
# ./render.sh model.scad -> model.gif (orbit)
|
||||
# ./render.sh model.scad out.gif -> out.gif
|
||||
# ./render.sh --sheet model.scad -> model.sheet.png (iso/front/right/top)
|
||||
#
|
||||
# Env knobs (sane defaults):
|
||||
# FRAMES=36 SIZE=520 ELEV=62 FPS=24 COLORSCHEME=Tomorrow BG=#0d1117
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# --- locate the OpenSCAD CLI (snapshot/nightly first, then stable) ------------
|
||||
find_openscad() {
|
||||
if [[ -n "${OPENSCAD_BIN:-}" && -x "${OPENSCAD_BIN}" ]]; then echo "${OPENSCAD_BIN}"; return; fi
|
||||
for c in \
|
||||
"/Applications/OpenSCAD (Nightly).app/Contents/MacOS/OpenSCAD" \
|
||||
"/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD" \
|
||||
"$(command -v openscad 2>/dev/null || true)"; do
|
||||
[[ -n "$c" && -x "$c" ]] && { echo "$c"; return; }
|
||||
done
|
||||
echo "ERROR: OpenSCAD CLI not found. Set OPENSCAD_BIN." >&2; exit 1
|
||||
}
|
||||
OSCAD="$(find_openscad)"
|
||||
|
||||
# BOSL2 / BOSL / MCAD live here (unzipped from public/libraries/*.zip).
|
||||
export OPENSCADPATH="${OPENSCADPATH:-/tmp/oscad-libs}"
|
||||
|
||||
FRAMES="${FRAMES:-36}"
|
||||
SIZE="${SIZE:-520}"
|
||||
ELEV="${ELEV:-62}"
|
||||
FPS="${FPS:-24}"
|
||||
COLORSCHEME="${COLORSCHEME:-Tomorrow}" # clean near-white backdrop
|
||||
RENDER_FLAG="${RENDER_FLAG:---render}" # full (manifold) render; --preview is faster but CSG-fuzzy
|
||||
|
||||
SHEET=0
|
||||
if [[ "${1:-}" == "--sheet" ]]; then SHEET=1; shift; fi
|
||||
|
||||
SRC="${1:?usage: render.sh [--sheet] model.scad [out.(gif|png)]}"
|
||||
BASE="$(basename "${SRC%.scad}")"
|
||||
DIR="$(cd "$(dirname "$SRC")" && pwd)"
|
||||
OUT="${2:-}"
|
||||
|
||||
delay=$(awk "BEGIN{printf \"%.0f\", 100/${FPS}}")
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
render_frame() { # rotx roty rotz file
|
||||
"$OSCAD" -o "$4" --imgsize="${SIZE},${SIZE}" --projection=perspective \
|
||||
--colorscheme="$COLORSCHEME" $RENDER_FLAG --viewall --autocenter \
|
||||
--camera="0,0,0,$1,$2,$3,0" "$SRC" 2>"$tmp/err.log" || {
|
||||
echo "OpenSCAD failed on $SRC:" >&2; cat "$tmp/err.log" >&2; exit 1; }
|
||||
}
|
||||
|
||||
if [[ "$SHEET" == "1" ]]; then
|
||||
OUT="${OUT:-$DIR/$BASE.sheet.png}"
|
||||
render_frame 62 0 25 "$tmp/iso.png"
|
||||
render_frame 90 0 0 "$tmp/front.png"
|
||||
render_frame 90 0 90 "$tmp/right.png"
|
||||
render_frame 0 0 0 "$tmp/top.png"
|
||||
magick montage "$tmp/iso.png" "$tmp/front.png" "$tmp/right.png" "$tmp/top.png" \
|
||||
-label '' -tile 2x2 -geometry +6+6 -background white "$OUT"
|
||||
echo "wrote $OUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
OUT="${OUT:-$DIR/$BASE.gif}"
|
||||
echo "rendering $FRAMES frames of $BASE ..."
|
||||
i=0
|
||||
while [[ $i -lt $FRAMES ]]; do
|
||||
az=$(awk "BEGIN{printf \"%.2f\", $i*360/$FRAMES}")
|
||||
printf -v n "%03d" "$i"
|
||||
render_frame "$ELEV" 0 "$az" "$tmp/f_$n.png"
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
echo "assembling $OUT ..."
|
||||
magick -delay "$delay" -loop 0 "$tmp"/f_*.png \
|
||||
-layers OptimizePlus -fuzz 3% -colors 200 "$OUT"
|
||||
# second pass: strip + max compression
|
||||
magick "$OUT" -strip -layers Optimize "$OUT"
|
||||
echo "wrote $OUT ($(du -h "$OUT" | cut -f1))"
|
||||
Reference in New Issue
Block a user