ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / vidwhacker
diff --git a/hacks/vidwhacker b/hacks/vidwhacker
new file mode 100755 (executable)
index 0000000..a27e0c2
--- /dev/null
@@ -0,0 +1,405 @@
+#!/bin/sh
+#
+# vidwhacker, for xscreensaver.  Copyright (c) 1998, 1999 Jamie Zawinski.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation.  No representations are made about the suitability of this
+# software for any purpose.  It is provided "as is" without express or 
+# implied warranty.
+#
+#
+# This script grabs a frame of video, then uses various pbm filters to
+# munge the image in random nefarious ways, then uses xv to put it on
+# the root window.  This works out really nicely if you just feed some
+# random TV station into it...
+#
+# The video grabbing part is SGI-specific -- if you want to use this on
+# another system, add a new clause to the grab() procedure.
+
+
+# need perl to generate random numbers -- I don't know another way to do
+# that from a shell script.
+perl=perl
+
+
+onroot=false
+verbose=false
+delay=3
+use_stdin=false
+use_stdout=false
+
+pid=""
+tmp=${TMPDIR:-/tmp}/vidwhacker.$$
+tmp_rgb=$tmp-00000.rgb
+tmp_ppm0=$tmp-0.ppm
+tmp_ppm1=$tmp-1.ppm
+tmp_ppm2=$tmp-2.ppm
+tmp_ppm3=$tmp-3.ppm
+tmp_ppm4=$tmp-4.ppm
+tmp_ppmS=$tmp-S.ppm
+
+
+# Process command-line args
+getargs() {
+
+  while [ $# != 0 ]; do
+    case "$1" in
+    -display | -disp | -dis | -dpy | -d )
+      shift
+      DISPLAY="$1"
+      export DISPLAY
+      ;;
+    -root )
+      onroot=true
+      ;;
+    -window )
+      onroot=false
+      ;;
+    -verbose )
+      verbose=true
+      ;;
+    -stdin )
+      use_stdin=true
+      ;;
+    -stdout )
+      use_stdout=true
+      ;;
+    -delay)
+      shift
+      delay="$1"
+      ;;
+    * )
+      echo "VidWhacker, Copyright (c) 1999 Jamie Zawinski <jwz@jwz.org>" >&2
+      echo "            http://www.jwz.org/xscreensaver/" >&2
+      echo "" >&2
+      echo "usage: $0 [-display dpy] [-verbose] [-root | -window]" >&2
+      echo "                  [-stdin] [-stdout] [-delay secs]" >&2
+      exit 1
+      ;;
+    esac
+    shift
+  done
+
+  xvargs="-quick24"
+
+  if [ "$onroot" = true ]; then
+    xvargs="$xvargs -root -rmode 5 -noresetroot -rfg black -rbg black -viewonly"
+  else
+    xvargs="$xvargs -geom +0+0"
+  fi
+
+
+  screen_width=''
+  if [ "$use_stdout" = false ]; then
+    screen_width=`xdpyinfo 2>/dev/null | 
+        sed -n 's/.* dimensions: *\([0-9]*\).*/\1/p'`
+    if [ "$screen_width" = "" ]; then
+      screen_width=800
+    fi
+  fi
+}
+
+
+clean() {
+  rm -f $tmp_rgb $tmp_ppm1 $tmp_ppm2 $tmp_ppm3 $tmp_ppm4
+}
+
+clean2() {
+  clean
+  rm -f $tmp_ppm0 $tmp_ppmS
+}
+
+
+# Grab a frame of video.  leaves it in $tmp_ppm1.
+#
+grab() {
+  uname=`uname`
+  if [ $uname = IRIX ]; then
+    #
+    # SGI's "vidtomem" returns an SGI RGB image of the default video input,
+    # and has stupid non-overridable ouput-file-naming conventions.  So, let 
+    # it write its file; and then convert it to a pgm.
+    #
+    
+    vidtomem -f $tmp
+    sgitopnm $tmp_rgb > $tmp_ppm1
+
+    # Cut off the close-captioning blips in the NTSC overscan region.  YMMV.
+    #  | pnmcut 12 7 695 477 
+
+  elif [ $uname = Linux ]; then
+
+    # Marcus Herbert says the following works with his Connectix Qcam.
+    # Don't have qcam?  Well, do something else then...  and send me a patch.
+
+    qcam > $tmp_ppm1
+
+    # Friedrich Delgado Friedrichs says the following works if you have
+    # XawTV installed:
+    #
+    #   streamer -o $tmp_ppm1
+    #
+
+  else
+    echo "$0: don't know how to grab video on this OS." >&2
+    clean2
+    exit 1
+  fi
+}
+
+
+# Use perl to pick a random foreground/background color in pbm's syntax.
+#
+randcolor() {
+  $perl -e 'srand(time ^ $$);
+            printf("#%02x%02x%02x-#%02x%02x%02x",
+                   int(rand()*60),
+                   int(rand()*60),
+                   int(rand()*60),
+                   120+int(rand()*135),
+                   120+int(rand()*135),
+                   120+int(rand()*135))'
+}
+
+rand() {
+  $perl -e "srand(time ^ $$); print int(rand() * $1)"
+}
+
+
+
+# Frobnicate the image in some random way.
+#
+frob() {
+
+  w_h=`head -2 $tmp_ppm1 | tail -1`
+  width=`echo $w_h | awk '{print $1}'`
+  height=`echo $w_h | awk '{print $2}'`
+
+  N=`rand 17`
+
+  if [ "$verbose" = true ]; then
+    echo "mode $N..." >&2
+  fi
+
+  if   [ $N = 0 ]; then
+    ppmtopgm $tmp_ppm1 | pgmedge | pgmtoppm `randcolor` | ppmnorm
+
+  elif [ $N = 1 ]; then
+    ppmtopgm $tmp_ppm1 | 
+    pgmenhance | 
+    pgmtoppm `randcolor`
+
+  elif [ $N = 2 ]; then
+    ppmtopgm $tmp_ppm1 | pgmoil | pgmtoppm `randcolor`
+
+  elif [ $N = 3 ]; then 
+    ppmrelief $tmp_ppm1 | ppmtopgm | pgmedge | ppmrelief | ppmtopgm |
+      pgmedge | pnminvert | pgmtoppm `randcolor`
+
+  elif [ $N = 4 ]; then
+    ppmspread 71 $tmp_ppm1 > $tmp_ppm2
+    pnmarith -add $tmp_ppm1 $tmp_ppm2
+
+  elif [ $N = 5 ]; then
+    pnmflip -lr $tmp_ppm1 > $tmp_ppm2
+    pnmarith -multiply $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
+    pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
+    pnmarith -multiply $tmp_ppm1 $tmp_ppm2
+
+  elif [ $N = 6 ]; then
+    N2=`rand 3`
+    if [ $N2 = 0 ]; then
+      pnmflip -lr $tmp_ppm1 > $tmp_ppm2
+    elif [ $N2 = 1 ]; then
+      pnmflip -tb $tmp_ppm1 > $tmp_ppm2
+    else
+      pnmflip -lr $tmp_ppm1 > $tmp_ppm2
+      pnmflip -tb $tmp_ppm2 > $tmp_ppm3
+      cp $tmp_ppm3 $tmp_ppm2
+    fi
+
+    pnmarith -difference $tmp_ppm1 $tmp_ppm2
+
+  elif [ $N = 7 ]; then
+
+    for i in 1 2 3 ; do
+      ppmtopgm $tmp_ppm1 | pgmedge > $tmp_ppm2
+      pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
+      cp $tmp_ppm3 $tmp_ppm1
+    done
+    ppmnorm < $tmp_ppm1
+
+  elif [ $N = 8 ]; then
+    pnmflip -lr $tmp_ppm1 > $tmp_ppm2
+    pnmarith -multiply $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmnorm | pnminvert
+
+  elif [ $N = 9 ]; then
+    pnmflip -lr $tmp_ppm1 > $tmp_ppm2
+    pnmarith -subtract $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmtopgm | pgmedge
+
+  elif [ $N = 10 ]; then
+    ppmtopgm $tmp_ppm1 | pgmbentley | pgmtoppm `randcolor`
+
+  elif [ $N = 11 ]; then
+    pgmcrater -number 20000 -height $height -width $width | pgmtoppm `randcolor` > $tmp_ppm2
+    pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
+    pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
+    pnmarith -multiply $tmp_ppm1 $tmp_ppm2
+
+  elif [ $N = 12 ]; then
+    ppmshift 30 $tmp_ppm1 | ppmtopgm | pgmoil | pgmedge |  pgmtoppm `randcolor` > $tmp_ppm2
+    pnmarith -difference $tmp_ppm1 $tmp_ppm2 
+
+ elif [ $N = 13 ]; then
+    ppmpat -madras $width $height | pnmdepth 255 > $tmp_ppm2
+    pnmarith -difference $tmp_ppm1 $tmp_ppm2
+  elif [ $N = 14 ]; then
+    ppmpat -tartan $width $height | pnmdepth 255 > $tmp_ppm2
+    pnmarith -difference  $tmp_ppm1 $tmp_ppm2 
+  
+  elif [ $N = 15 ]; then
+    ppmpat -camo $width $height | pnmdepth 255 | ppmshift 50 > $tmp_ppm2
+    pnmarith -multiply $tmp_ppm1 $tmp_ppm2
+  
+  elif [ $N = 16 ]; then
+    pgmnoise $width $height | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2
+    pnmarith -difference $tmp_ppm1 $tmp_ppm2 | pnmdepth 255 | pnmsmooth
+
+  else cat $tmp_ppm1
+  fi
+}
+
+
+# Grab a frame and frob it.  leave it in $tmp_ppm3.
+#
+whack() {
+  clean
+
+  while [ ! -f $tmp_ppm1 ]; do
+    if [ "$use_stdin" != true ]; then
+      grab
+    else
+      cp $tmp_ppmS $tmp_ppm0
+      cp $tmp_ppm0 $tmp_ppm1
+    fi
+  done
+
+  rm -f $tmp_rgb
+
+  if [ "$screen_width" != "" ]; then
+    frob | pnmscale -width $screen_width > $tmp_ppm3
+  else
+    frob > $tmp_ppm3
+  fi
+
+  rm -f $tmp_ppm1 $tmp_ppm2
+}
+
+
+# Kill off the xv subprocess, if it's running
+#
+kill_pid() {
+  if [ "$pid" != "" ]; then
+
+    if [ "$verbose" = true ]; then
+      echo "killing pid $pid..." >&2
+    fi
+
+    # need to do this to avoid "6898 Terminated" messages!
+    # apparently one can't redirect the output of the builtin `kill' command.
+#    ( sh -c "kill $pid" ) >/dev/null 2>/dev/null </dev/null
+
+    # wtf?  that doesn't work either.  Is it writing to /dev/tty??
+    kill $pid >/dev/null 2>&1
+
+    pid=""
+  fi
+}
+
+# called when this process is signalled (for cleanup)
+#
+my_trap() {
+  if [ "$verbose" = true ]; then
+    echo "trapped signal!" >&2
+  fi
+  kill_pid
+  clean2
+  exit 1
+}
+
+main() {
+
+  getargs $@
+
+  trap my_trap 1 2 3 6 9 13 15
+
+  if [ "$use_stdin" = true ]; then
+   cat > $tmp_ppmS
+  fi
+
+  while true; do
+
+    # Loop grabbing and frobbing images.
+    #
+    # If we're running on the root, run xv in the foreground (with -exit)
+    # and then wait.
+    #
+    # If we're running in a window, spawn xv in the background; then when
+    # it's time to put up the new image, kill off the currently-running xv.
+
+    if [ "$verbose" = true ]; then
+      whack
+    else
+      whack >/dev/null 2>&1
+    fi
+
+    kill_pid
+
+    if [ ! -s $tmp_ppm3 ]; then
+      echo "$0: no image grabbed" >&2
+
+    elif [ "$use_stdout" = true ]; then
+
+      cat $tmp_ppm3
+      clean2
+      exit 0
+
+    else
+
+      pnmtosgi < $tmp_ppm3 > $tmp_ppm2
+      rm -f $tmp_ppm3
+
+      if [ -s $tmp_ppm2 ]; then
+        if [ "$verbose" = true ]; then
+          echo "launching xv $xvargs $tmp_ppm2" >&2
+         ls -lF $tmp_ppm2
+        fi
+
+       mv $tmp_ppm2 $tmp_ppm0
+        xv $xvargs $tmp_ppm0 &
+
+# this doesn't work -- leaves xv processes around, instead of stray xset
+# data.  Sigh.
+#
+#      # cat the file so that we can nuke it without racing against xv.
+#        cat $tmp_ppm2 | xv $xvargs - &
+
+        pid=$!
+      fi
+    fi
+
+    clean
+    sleep $delay
+
+  done
+  exit 1
+}
+
+main $@
+
+# to find stray xv data:
+# xwininfo -root -children|grep 'xv image comments' | awk '{print "xkill -id ", $1}'