#! /bin/bash
# Last edited on 2019-04-05 21:12:49 by stolfilocal

usage="$0 [ -fast | -fair | -good | -quick ] [ -detail XMIN XMAX YMIN YMAX ] [ -segment XSEG/NX YSEG/NY ] [ -tiny | -small | -plain | -big | -size WD HT ] [ -scale s ] [ -in DIR [ -norender ] ] [ -list DIRLIST ] [ -hist ] [ -qmethod {fs|near|noquant} ] [ -transparent | -blackbg | -whitebg ] [ -show|-noshow ] [ -noindex ] [ -preview ] NAME.pov"

######################################################################
# Generates POVRAY rendering of a scene (PNG output)
# 
# By default, all output (incluring a copy of all scene sources) goes
# to a subdirectory whose name is the current date and time. The
# subdirectory is automatically deleted if the run fails. Otherwise
# the subdirectory's name is stored in the files ".last" in the
# current directory, and appended to the file DIRLIST (which defaults
# to "NAME.dirlist"). Also a symbolic link ".lastdir" is made to point
# to it.
# 
# The current directory may include a file called NAME.sizes
# redefining the sh variables
#   ${tinysize}   default ( 050 050 )
#   ${smallsize}  default ( 100 100 )
#   ${plainsize}  default ( 200 200 )
#   ${bigsize}    default ( 400 400 )
# 
# The current directory may also include files called NAME.options
# and povray.options, with additional options to be passed to POVRAY
# (for instance, "+L" options).
# 
# The "-transparent" flag runs povray twice, with black and white
# background, and then combines them into an RGBA
# (partially-transparent) png. The "-blackbg" and "-whitebg" options
# create only one of the two images, and will not create the
# semi-transparent version. In either case, the NAME.pov file should
# "#include" the file "background.inc", generated by this script, which
# will contain
# 
#    #declare bgColor = color rgb <...>
#    background {color bgColor}
# 
# The "-in" flag specifies that povray should be run in an existing
# directory DIR, which should contain all the necessary files. In this
# case, DIR is not removed if the run fails. This option is useful to
# re-run an old run with, say, increased resolution or improved tools.
# 
# The "-norender" option can be used in conjuntion with "-in" to force
# the re-conversion of existing ".ppm" files to ".png".
# 
# The "-preview" option displays a coarse preview of the image while
# rendering.
# 
# The option "-segment XSEG/NX YSEG/NY" adds declarations 
#   segment_h = XSEG   segment_h_num = NX
#   segment_v = YSEG   segment_h_num = NY
# to the background.inc file.
# 
# If "-qmethod" is anything other than "noquant" (the default),
# then the resulting image will be color-reduced with ppmvquant 
# or ppmoquant.
# 
# By default, the script rebulds the picture index in the 
# current directory ("index.html").  Use "-noindex" to supress it.
# 
######################################################################

#### Commands executed in the scene directory ########################
# 

# Clear the ".last" file (name of last render directory):
echo "NONE" > .last
 
povbin="/usr/bin"
postertools="${STOLFIHOME}/posters/tools"
povray=${povbin}/povray

path=( ${postertools} ${povbin} ${path} )

cmdname="$0"
runargs="$@"
echo "${cmdname} ${runargs}" 1>&2

size=( "plain" )
rays=3
qual=9
transp=0
scaleopts=( )
viewopts=( )
show=0
# show=1
render=1
makeindex=1
givendir=
dirlist=
detailopts=( )
# histopts=( "+HTX" )
histopts=( )
quantopts=( )
segments=( )
bgrounds=( 1 )

while [[ ( $# -gt 0 ) && ( "/${1:0:1}" == "/-" ) ]]; do
  if [[ "/$1" == "/-show" ]]; then
    show=1; shift
  elif [[ "/$1" == "/-noshow" ]]; then
    show=0; shift
  elif [[ "/$1" == "/-noindex" ]]; then
    makeindex=0; shift
  elif [[ "/$1" == "/-norender" ]]; then
    render=0; shift
  elif [[ "/$1" == "/-hist" ]]; then
    histopts=( "+HTP" ); shift
  elif [[ "/$1" == "/-preview" ]]; then
    viewopts=( "+D" "+SP32" "+EP4" ); shift
  elif [[ ( $# -ge 5 ) && ( "/$1" == "/-detail" ) ]]; then
    detailopts=(  "+SC$2" "+EC$3" "+SR$4" "+ER$5" ); 
    shift; shift; shift; shift; shift
  elif [[ ( $# -ge 3 ) && ( "/$1" == "/-segment" ) ]]; then
    segments=( $2 $3 ); shift; shift; shift
  elif [[ "/$1" == "/-quick" ]]; then 
    rays=1; qual=4; shift
  elif [[ "/$1" == "/-fast" ]]; then
    rays=1; qual=9; shift
  elif [[ "/$1" == "/-fair" ]]; then
    rays=2; qual=9; shift
  elif [[ "/$1" == "/-good" ]]; then
    rays=4; qual=9; shift
  elif [[ "/$1" == "/-tiny" ]]; then
    size=( "tiny" ); shift
  elif [[ "/$1" == "/-small" ]]; then
    size=( "small" ); shift
  elif [[ "/$1" == "/-plain" ]]; then
    size=( "plain" ); shift
  elif [[ "/$1" == "/-big" ]]; then
    size=( "big" ); shift
  elif [[ ( $# -ge 3 ) && ( "/$1" == "/-size" ) ]]; then
    size=( $2 $3 ); shift; shift; shift
  elif [[ ( $# -ge 2 ) && ( "/$1" == "/-qmethod" ) ]]; then
    quantopts=( "-qmethod" "$2" );  shift; shift
  elif [[ ( $# -ge 2 ) && ( "/$1" == "/-scale" ) ]]; then
    scaleopts=( "-scale" "$2" );  shift; shift;
  elif [[ "/$1" == "/-transparent" ]]; then
    transp=1;  bgrounds=( 0 1 );  shift
  elif [[ "/$1" == "/-blackbg" ]]; then
    transp=1;  bgrounds=( 0 ); shift
  elif [[ "/$1" == "/-whitebg" ]]; then
    transp=1;  bgrounds=( 1 ); shift
  elif [[ ( $# -ge 3 ) && ( "/$1" == "/-in" ) ]]; then
    givendir="$2";  shift; shift
  elif [[ ( $# -ge 3 ) && ( "/$1" == "/-list" ) ]]; then
    dirlist="$2";  shift; shift
  else
    echo 'bad option "'"$1"'"' 1>&2 
    echo "usage: ${usage}" 1>&2; exit 1
  fi
done

if [[ ( ${render} -eq 0 ) && ( "/${givendir}" == "/" ) ]]; then
  echo 'option "-norender" can be used only with "-in DIR"' 1>&2
  echo "usage: ${usage}" 1>&2; exit 1
fi

if [[ $# -ne 1 ]]; then
  echo "usage: ${usage}" 1>&2; exit 1
fi
 
name="$1"
if [[ "/${name##*.}" != "/pov" ]]; then
  echo "usage: ${usage}" 1>&2; exit 1
fi
name=${name%.*}

if [[ ! ( "/${dirlist}" != "/" ) ]]; then
  dirlist="${name}.dirlist"
fi

if [[ "/${givendir}" != "/" ]]; then
  if [[ ! ( -d ${givendir} ) ]]; then
    echo "${givendir}: not a directory" 1>&2; exit 1
  fi
  d="${givendir}"
  echo "re-generating picture in directory ${d}" 1>&2
  if [[ ${render} -ne 0 ]]; then
    if [[ -r ${d}/run-povray.args ]]; then
      /bin/mv ${d}/run-povray.args ${d}/run-povray.args~
    fi
    echo "on `date +%Y-%m-%d-%H%M%S`:" >> ${d}/${name}.comments
    if [[ -r ${name}.comments ]]; then
      cat ${name}.comments >> ${d}/${name}.comments
    fi
  fi
else
  d=`date +%Y-%m-%d-%H%M%S`
  echo "generating picture in directory ${d}" 1>&2
  mkdir ${d}
  cp -a ${name}.pov ${d}
  shopt -sq nullglob
  cp -a $0 [a-zA-Z0-9]*.{inc,incx,gif,png,csh,sh,make,awk} ${d}
  shopt -uq nullglob
  for f in ${name}.{ini,sizes,options,comments} povray.options do-run-povray ; do
    if [[ -s ${f} ]]; then
      cp -pv ${f} ${d}
    fi
  done
fi

#
######################################################################

curd="${PWD}"
cd ${d}
pwd

#### Commands executed in the run sub-directory ######################
# 

if [[ ${#size[@]} -eq 1 ]]; then
  if [[ -s ${name}.sizes ]]; then
    # The file ${name}.sizes ought to define "${tinysize}" "${smallsize}" "${plainsize}" "${bigsize}".
    # Convert old "csh" format to "bash" format if necessary:
    cat ${name}.sizes \
      | sed \
          -e 's:^set *::g' \
          -e 's: *= *:=:g' \
          -e 's:\( [0-9][0-9]*\): "\1":g' \
      > .sizes
    source .sizes
  fi
  if [[ "/${tinysize[@]}" == "/" ]];  then tinysize=(  );  fi
  if [[ "/${smallsize[@]}" == "/" ]]; then smallsize=(  ); fi
  if [[ "/${plainsize[@]}" == "/" ]]; then plainsize=(  ); fi
  if [[ "/${bigsize[@]}" == "/" ]];   then bigsize=(  );   fi
  if [[ "${size[0]}" == "tiny" ]]; then
    size=( ${tinysize[@]} )
  elif [[ "${size[0]}" == "small" ]]; then
    size=( ${smallsize[@]} )
  elif [[ "${size[0]}" == "plain" ]]; then
    size=( ${plainsize[@]} )
  elif [[ "${size[0]}" == "big" ]]; then
    size=( ${bigsize[@]} )
  else 
    echo "run-povray: internal bug (size = ${size[@]})" 1>&2
    exit 1
  fi
fi

if [[ -r ${name}.options ]]; then
  nameopts=( `cat ${name}.options` )
else
  nameopts=( )
fi
if [[ -r povray.options ]]; then
  povopts=( `cat povray.options` )
else
  povopts=( )
fi

if [[ ${render} -ne 0 ]]; then
  echo "${cmdname} ${runargs}" > run-povray.args
  echo "[`uname -n`] ${cmdname##*/} ${runargs}" >> ${name}.comments

  if [[ -r ${name}.make ]]; then
    make -f ${name}.make all \
      2>&1 | tee ${name}.make.log
  fi
fi

# Remove any old output image files:
/bin/rm -f ${name}.{ppm,png} ${name}-{0,1}.{ppm,png} ${name}-icon.png

# Remove any old symbolic links:
/bin/rm -f p.{ppm,png} p-{0,1}.{ppm,png} p-icon.png p.comments

# Termination status of povray command:
povrayok=1

# Create background/segment file:
/bin/rm -f background.inc
if [[ ${#segments[@]} -gt 0 ]]; then
  echo "#declare segment_h     = ${segments[0]%%/*};" >> background.inc
  echo "#declare segment_h_num = ${segments[0]##*/};" >> background.inc
  echo "#declare segment_v     = ${segments[1]%%/*};" >> background.inc
  echo "#declare segment_v_num = ${segments[1]##*/};" >> background.inc
fi

# Set ${inifile} to list with the ".ini" file if present, else set it to empty list
if [[ -s "${name}.ini" ]]; then
  inifile=( "${name}.ini" )
  printf -- "--- ${name}.ini ---\n" >> ${name}.comments
  cat ${name}.ini >> ${name}.comments
else
  inifile=()
fi

# define the common POV-Ray options:
povops=( \
  +Q${qual} +R${rays} +W"${size[0]}" +H"${size[1]}" \
  +AM1 +A0.0 +MB1 \
  ${viewopts[@]} ${povopts[@]} ${nameopts[@]} ${detailopts[@]} \
  +L${STOLFIHOME}/PUB/povray +L.. \
  +GI${name}-restart.ini \
  -GS -GR \
  +I${name}.pov \
)
printf -- "--- povray command line options ---\n" >> ${name}.comments
printf "  %s\n" "${povops[@]}" >> ${name}.comments

if [[ ${transp} -eq 0 ]]; then
  if [[ ${render} -ne 0 ]]; then
    # run povray once, with gray background:
    echo "=== generating png image ===" 1>&2
    echo "#declare bgColor = color rgb <0.5,0.5,0.5>;" >> background.inc
    echo "#declare bg_color = bgColor;" >> background.inc
    echo "background { color bg_color }" >> background.inc
    ${povray} \
        ${inifile[@]} \
        ${povops[@]} \
        +FN +O${name}.png \
        2>&1 \
      | tee povray.log \
      | ${postertools}/reformat-povray-output.gawk
    if [[ ! ( -s ${name}.png ) ]]; then
      povrayok=0
    fi
  fi
  
# ${histopts[@]} +HN${name}-time.ppm \

  if [[ ${povrayok} -ne 0 ]]; then
    convert ${name}.png -resize 'x50' ${name}-icon.png
    ln -s ${name}.png p.png
    ln -s ${name}.comments p.comments
    ln -s ${name}-icon.png p-icon.png
  fi
else
  if [[ ${render} -ne 0 ]]; then
    # run povray twice, with black and white backgrounds:
    for bg in ${bgrounds[@]} ; do
      echo "=== generating ppm image with background = ${bg} ===" 1>&2
      echo "#declare bgColor = color rgb <${bg}, ${bg}, ${bg}>;" >> background.inc
      echo "background { color bgColor }" >> background.inc
      ${gnice[@]} ${povray} \
          ${inifile[@]} \
          ${povops[@]} \
          +FP +O${name}-${bg}.ppm \
          2>&1 \
        | tee povray-${bg}.log \
        | ${postertools}/reformat-povray-output
      if [[ ! ( -s ${name}-${bg}.ppm ) ]]; then
        povrayok=0
        break
      else
        ln -s ${name}-${bg}.ppm p-${bg}.ppm
      fi
    done
  fi

  if [[ ( ${povrayok} -ne 0 ) && ( -s ${name}-0.ppm ) && ( -s ${name}-1.ppm ) ]]; then
    linear-ppm-pair-to-png ${quantopts[@]} ${scaleopts[@]} ${name}-{0,1}.ppm > ${name}.png
    ln -s ${name}.png p.png
    ln -s ${name}.comments p.comments

    linear-ppm-pair-to-png ${quantopts[@]} -ysize 50 ${name}-{0,1}.ppm > ${name}-icon.png
    ln -s ${name}-icon.png p-icon.png
  fi
fi

if [[ ${render} -ne 0 ]]; then
  if [[ -s ${name}.make ]]; then
    make -f ${name}.make clean
  fi
fi

#
######################################################################

cd ${curd}
pwd

#### Commands executed in the scene directory ########################
# 

if [[ -s ${d}/${name}.png ]]; then
  echo 'rendering succeeded in directory '"${d}" 1>&2
  echo "${d}" > .last
  rm -f .lastdir; ln -s "${d}" .lastdir
  echo "${d}" >> ${dirlist}
  /bin/rm -f ${d}/${name}.html-inc ${d}/p.html-inc 
  make-image-index-entry ${d}/${name}.png > ${d}/${name}.html-inc
  ln -s ${name}.html-inc ${d}/p.html-inc   
  if [[ ${makeindex} -ne 0 ]]; then
    ${postertools}/make-povray-index
  fi
  if [[ ${show} -ne 0 ]]; then
    display -title '%d' ${d}/p.png ${d}/${name}*.{png,ppm} ${d}/p.comments
  fi
  exit 0
else
  echo 'rendering failed in directory '"${d}" 1>&2
  if [[ ( "/${givendir}" == "/" ) && ( ${povrayok} -eq 0 ) ]]; then
    echo "deleting directory ${d}" 1>&2
    /bin/rm -rf "${d}"
  fi
  exit 1
fi
