#!/bin/bash
#
# mk_vtsm - Create one or more chapter menus (titleset menus, vtsm)
#           for authoring a DVD with dvdauthor >= 0.6
#
# Version   0.4 written by Wolfgang Wershofen (mailto: itconsult at wershofen.de)
#           0.4.3: Menu multilingual 
#
# needs the following tools to run:
# - ImageMagick >= 5.5.4
# - toolame >= 0.2l
# - ppmtoy4m and mplex from mjpegtools >= 1.6.1
# - mpeg2enc from libmpeg2
# - spumux from dvdauthor >= 0.6.0
#
usage()
{
 cat <<EOF
Usage: `basename $0` [options] image-files

currently supported options:
----------------------------
-C | --config-file	filename of dvdwizard-configuration file
			[~/.dvdwizard/dvdwizard.conf]
-o | --output-dir	Define Output-Directory where ready-made menu-mpegs should
			be written to [.]
-x | --xml-file		Define filename for xml-definition
			[<output-dir>/dvdauthor.menu.xml]
-b | --vtsmbg		Image to use as background for chapter thumbnails.
			If not specified, mk_vtsm will create one from scratch
-r | --thumbaspectratio	Define the desired aspect ratio for the thumbnails [16:9]
-c | --chaptersperrow	Define how many chapter thumbnails will fit in a row [3]
-N | --tvnorm		TV-Norm to use <PAL|NTSC> [PAL]
-V | --tvsize		Visible area of frame on TV set. At least my tv does not
			show full "$normSize", but maybe yours can. [635x535]
-t | --vts		Titleset on the DVD where the menus should belong to [1]
--hasaudio		Title has multiple audio tracks. A button to jump to the audio
			selection menu will be created
--hasinfo		Title has EPG-Informations available. A button to jump to the
			info panel will be created (not yet implemented)
-h | --help		print this lot out

EOF
exit 1
}

# ------------------------------
# Main Processing
#
# We need some sub-routines from dvdwizardrc
# This file must reside in the same directory as the called script
# Should maybe go into a directory like /usr/local/share/dvdwizard
# but this would require an installation procedure - maybe in some
# later version.
#
rcfile="`dirname $0`/dvdwizardrc"
if [ -e "$rcfile" -a -r "$rcfile" ]; then
	. "$rcfile"
else
	echo "dvdwizardrc not found or is not readable. Aborting" >&2
    exit 1
fi

#
# Ok, first define some default values
#
set_defaults "$@"
VTSMDIR="."
vts=1
VTSMBG=""
fList=""
info=0
audio=0

#
# Now deal with command line arguments
#
while [ "$fList" == "" -a "$*" != "" ]; do
    case "$1" in
  	-h|--help)
   	    usage
  	;;
  	-C|--config-file)
    	shift
# -C and it's following parm already processed in set_defaults()
        shift
  	;;
	-o|--output)
 		shift
		VTSMDIR="$1"
	    shift
  	;;
  	-x|--xml)
	    shift
   	    XMLFILE="$1"
   	    shift
  	;;
  	-t|--vts)
	    shift
   	    vts="$1"
   	    shift
	;;
  	-b|--vtsmbg)
	    shift
   	    VTSMBG="$1"
   	    shift
  	;;
  	-N|--tvnorm)
	    shift
   	    TVNORM="$1"
            if [ "$TVNORM" == "PAL" -o "$TVNORM" == "NTSC" ]; then
        	:
            else
        	echo "Incorrect TV-Norm $TVNORM specified, only PAL and NTSC are supported. Aborting" >&2
            	usage
            fi
   	    shift
  	;;
  	-V|--tvsize)
	    shift
   	    TVSIZE="$1"
   	    shift
  	;;
  	--hasinfo)
  	    info="1"
   	    shift
  	;;
  	--hasaudio)
  	    audio="1"
   	    shift
  	;;
  	-c|--chaptersperrow)
   		shift
   		CHAPTERSPERROW="$1"
   		shift
  	;;
  	-r|--thumbaspectratio)
   		shift
   		THUMBRATIO="$1"
   		shift
  	;;
  	*)
   		fList="$@"
  	;;
    esac
done

#
# Let's see, if all options are correct
# Check output-directories and files
#
mk_check_dir "$VTSMDIR" "NEW"
mk_check_dir "$TMPDIR" "NEW"
mk_check_file "$XMLFILE" "NEW"
[ ! -z "$VTSMBG" ] && mk_check_file "$VTSMBG" "OLD"

#
# Chapter-Pictures supplied and existing?
#
if [ -z "$fList" ]; then
 	echo "No input files specified" >&2
 	usage
fi

for i in "$@"; do
	mk_check_file "$i" "OLD"
done

#
# Do some file and directory preparation
#
ls -d "$TMPDIR"/tmp_mk_vtsm* > /dev/null 2>&1 && rm -R "$TMPDIR"/tmp_mk_vtsm*
workDir=`mktemp -d "$TMPDIR"/tmp_mk_vtsm_XXXXXX`
spuxml="$workDir"/tmp_spumux.xml

#
# Create an empty audio track for the menu mpeg
#
create_silence

#
# Prepare the background picture
# ($VMGMBG will be converted to $workbg)
#
prepare_bg "$VTSMBG"
panelsize=150
menupanel="$workDir"/tmp_panel.png
menuBG="$workDir"/tmp_menu_bg.png
convert -size "$panelsize"x"$tvY" xc:'rgba(255,255,255,96)' "$menupanel"  || error_out
convert -scale "$normSize"! -density "$normDensity" -units PixelsPerInch "$workbg" ppm:- | \
composite -compose Over -geometry +"$offsetX"+"$offsetY" "$menupanel" - "$menuBG" || error_out

#
# Calculation of thumbnail sizes and how many thumbs will fit on one page
#
bs=3
gap=8
THUMBRATIOX=`echo $THUMBRATIO | cut -d: -f 1`
THUMBRATIOY=`echo $THUMBRATIO | cut -d: -f 2`
bordersize="$bs"x"$bs"
borderspace="$gap"x"$gap"
let patchX=($tvX-150)/$CHAPTERSPERROW
let thumbX=$patchX-$bs*2-$gap*2
let thumbY=$thumbX/$THUMBRATIOX*$THUMBRATIOY
thumbsize="$thumbX"x"$thumbY"
let patchY=$thumbY+$bs*2+$gap*2
patchsize="$patchX"x"$patchY"
let cpc=$tvY/$patchY
let cpm=$CHAPTERSPERROW*$cpc
tiles="$CHAPTERSPERROW"x"$cpc"

#
# Now create the button masks for the three button states (unselected, highlighted, selected)
#
color=( white red yellow )
suffix=( u h s )
emptybutton="$workDir"/tmp_empty_button.png
convert -size $patchsize xc:transparent -density "$normDensity" -units PixelsPerInch "$emptybutton" || error_out
for i in 0 1 2; do
   bmask[i]="$workDir"/tmp_bmask_"${suffix[i]}".png
   convert -size $thumbsize xc:transparent -density "$normDensity" -units PixelsPerInch \
           -bordercolor "${color[i]}" -border $bordersize \
           -bordercolor transparent -border $borderspace "${bmask[i]}" || error_out
done

#
# Create thumbnails from image files specified on the command line
#
echo -n "Creating Chapter-Thumbnails"
workpng="$workDir"/tmp_thumbnail.png
bnum=0
[ 0"$IM_VERSION" -lt 6 ] && yOffset=30 || yOffset=10
for i in "$@"; do
 	echo -n "."
 	let bnum+=1
 	cPic[bnum]="$workDir"/tmp_chapter$bnum.png
 	convert -trim -scale "$thumbsize"! -density "$normDensity" -units PixelsPerInch "$i" "$workpng" || error_out
 	convert -size $thumbsize xc:transparent -pointsize $MFONTSIZE \
	        -fill 'rgba(255,255,255,128)' -draw 'gravity SouthEast text 12,'$(( $yOffset+2 ))' "'$bnum'"' \
			-fill 'rgba(0,0,0,128)' -draw 'gravity SouthEast text 10,'$yOffset' "'$bnum'"' \
	        +antialias -fill green  -draw 'gravity SouthEast text 11,'$(( $yOffset+1))' "'$bnum'"' \
	        -transparent green png:- | \
		composite -compose Over -gravity Center - "$workpng" png:- | \
		convert -bordercolor transparent -border $bordersize -border $borderspace - "${cPic[bnum]}" || error_out
done
numChapters=$bnum
echo "done. Created $bnum Thumbnails."

#
# Calculate how many menus are needed to hold all chapters and define corresponding button text
#
let "menucount=(($numChapters-1)/$cpm)+1"

for ((mnum=1; mnum <= menucount ; mnum++)); do
   let "fchap=($mnum-1)*$cpm+1"
   let "lchap=($mnum*$cpm)"
   [ $lchap -gt $numChapters ] && lchap=$numChapters
   btext[mnum]="$TEXT_CHAPTER_FROM $fchap $TEXT_CHAPTER_TO $lchap"
   echo "Menu $mnum: ${btext[mnum]}"
done

#
# Start XML-Definition for the menu
#
echo -e "\t\t<menus>" >> "$XMLFILE"

#
# Well now, here we go - Montage the images needed to build a menu
# in turn, output the xml-commands for dvdauthor
#
echo "Creating Menu(s)"
mnum=1
cnum=1
entry="entry=\"ptt\""

#
# This is the outer loop for all chapters. Every new menu starts here
#
while [ $cnum -le $numChapters ]; do
 	bnum=1
 	bcount=1
 	firstchapter=$cnum

#
# Empty Picturelists; Lists contain the filenames of the thumbnails which will later on
# be composed together
#
 	picList=""
 	for i in 0 1 2; do
	   	maskList[i]=""
 	done

#
# Ok, define the pgc for the menu and define the intra-menu-navigation buttons
#
    echo -e "\t\t\t<pgc $entry pause=\"0\">" >> "$XMLFILE"
    echo -e "\t\t\t\t<pre> { if (g1 lt 9) g1=1; if (g2 lt 1024) button=1024; else button=g2; } </pre>" >> $XMLFILE
	vob="$VTSMDIR"/vtsm"$vts"_"$mnum".mpg
 	echo -e "\t\t\t\t<vob file=\"$vob\" pause=\"inf\"/>" >> "$XMLFILE"

#
# This is for intra menu navigation
#
    for ((i=1; i <= menucount ; i++)); do
    	if [ $i -ne $mnum ]; then
       	echo -e "\t\t\t\t<button name=\"$bnum\"> { g2=button; jump menu $i; } </button>" >> "$XMLFILE"
       	let bnum+=1
    	fi
 	done
#
# if we have multiple audio tracks, make a button to jump to the audio selection menu
#
	if [ $audio -eq 1 ]; then
 		echo -e "\t\t\t\t<button name=\"$bnum\"> { g2=button; jump menu entry audio; } </button>" >> "$XMLFILE"
   		let bnum+=1
   	fi

#
# if we have some info text, make a button to jump to the info display Menu
# (Multi-Angle-Menu is misused for that purpose
#
	if [ $info -eq 1 ]; then
 		echo -e "\t\t\t\t<button name=\"$bnum\"> { g2=button; jump menu entry angle; } </button>" >> "$XMLFILE"
   		let bnum+=1
   	fi
#
# Return to the Title-Menu of the DVD
#
    echo -e "\t\t\t\t<button name=\"$bnum\"> { g2=button; jump vmgm menu entry title; } </button>" >> "$XMLFILE"
 	let bnum+=1

#
# The Resume Button
#
    echo -e "\t\t\t\t<button name=\"$bnum\">" >> "$XMLFILE"
    echo -e "\t\t\t\t\t{ g2=button; if (g1 lt 9) jump vmgm menu entry title;" >> "$XMLFILE"
    echo -e "\t\t\t\t\t  if (g1 eq 9) resume; }" >> "$XMLFILE"
    echo -e "\t\t\t\t</button>" >> "$XMLFILE"

#
# Go for the chapter buttons
#
 	let bnum+=1
    firstthumb=$bnum
 	entry=""
 	while [ $bcount -le $cpm ]; do
  		if [ $cnum -le $numChapters ]; then
   			newPic="${cPic[cnum]}"
   			for i in 0 1 2; do
      			newMask[i]="${bmask[i]}"
   			done
   			let cnum+=1
   			let bnum+=1
  		else
      		newPic="$emptybutton"
   			for i in 0 1 2; do
      			newMask[i]="$emptybutton"
   			done
  		fi
  		picList="$picList $newPic"
  		for i in 0 1 2; do
     		maskList[i]="${maskList[i]} ${newMask[i]}"
  		done
  		let bcount+=1
 	done

#
# The following is an ugly hack, but I don't see any better solution at the moment
# To get a reliable button sequence in spumux autodetection, the buttons have to be ordered
# by columns first (top-bottom -> left-right)
# Since we're not Chinese, our common reading direction is (left-right -> top-bottom) and this
# way the chapters behind the buttons are ordered.
# The following code maps the buttons to the right chapters
#
 	let rows=($bnum-$firstthumb-1)/$CHAPTERSPERROW+1
 	col=0
 	row=0
 	for ((b=firstthumb; b <= bnum-1; b++)); do
    	let bchapter=$row*$CHAPTERSPERROW+$firstchapter+$col
		if [ $bchapter -le $numChapters ]; then
    	    echo -e "\t\t\t\t<button name=\"$b\"> { g2=button; jump title 1 chapter $bchapter; } </button>" >> "$XMLFILE"
		else
	    	let b-=1
		fi
    	let row+=1
    	if [ $row -ge $rows ]; then
       		let col+=1
       		row=0
    	fi
 	done

#
# Montage the menu background with the thumbnails and create the button-masks
#
	thumbPic1="$workDir"/tmp_thumbs1.png
	thumbPic2="$workDir"/tmp_thumbs2.png
  	maskPic1="$workDir"/tmp_buttons1.png
 	montage -background transparent -geometry $patchsize -tile $tiles $picList "$thumbPic1" || error_out
 	convert -size $TVSIZE xc:transparent png:- | \
 		composite -compose Over -gravity NorthEast "$thumbPic1" - "$thumbPic2" || error_out
 	for i in 0 1 2; do
   		maskPic2[i]="$workDir"/tmp_buttons2_$i.png
    	montage -background transparent -geometry $patchsize -tile $tiles ${maskList[i]} "$maskPic1" || error_out
    	convert -size $TVSIZE xc:transparent png:- | \
   		composite -compose Over -gravity NorthEast "$maskPic1" - "${maskPic2[i]}" || error_out

#
# This is for Intra-Menu-Navigation
# Button-Text is printed on the background-image, because the small font flickers on tv when
# specified in the mask-images
#
		scolor=black
        tcolor='rgb(128,128,196)'
		polyX1=5
		let polyX2=polyX1+15
	   	let polyX3=polyX1
	   	let textX=polyX1+20
	   	let shadowX=textX+1
	   	let lineX1=polyX1
	   	let lineX2=lineX1+120
	   	navy=10+$HFONTSIZE
		if [ $i -eq 0 ]; then
			mogrify -pointsize $HFONTSIZE \
   	     			-fill $scolor -draw 'text 6,'$(($HFONTSIZE/2+11))"$TEXT_CHAPTERS" \
   	     			-fill $tcolor -draw 'text 5,'$(($HFONTSIZE/2+10))"$TEXT_CHAPTERS" \
       	     		"$thumbPic2" || error_out
   		fi

#
# Print text and polygon for every chapter-menu
#
		for ((m=1; m <= menucount; m++)); do
 			let textY=$navy+$MFONTSIZE+5
   			let shadowY=$textY+1
      		let polyY1=$textY-$MFONTSIZE+3
      		let polyY3=$textY-3
      		let polyY2=$textY-$MFONTSIZE/2
      		let lineY=$polyY3+6
      		if [ ! $m -eq $mnum ]; then
         		if [ $i -eq 0 ]; then
            		mogrify -pointsize $MFONTSIZE \
               	     -fill $scolor -draw 'text '$shadowX','$shadowY' "'"${btext[m]}"'"' \
               	     -fill $tcolor -draw 'text '$textX','$textY' "'"${btext[m]}"'"' \
               	     "$thumbPic2" || error_out
         		else
          			mogrify +antialias -fill "${color[i]}" \
               	     -draw 'polygon '"$polyX1,$polyY1 $polyX2,$polyY2 $polyX3,$polyY3" \
		  					  -draw 'line '"$lineX1,$lineY $lineX2,$lineY" \
	            	     "${maskPic2[i]}"  || error_out
				fi
       		else
          		if [ $i -eq 2 ]; then
            		mogrify -pointsize $MFONTSIZE \
 	  	     		   -fill ${color[i]} -draw 'rectangle '"$polyX1,$polyY1 $polyX2,$polyY3" \
                       -fill $scolor -draw 'text '$shadowX','$shadowY' "'"${btext[m]}"'"' \
                       -fill $tcolor -draw 'text '$textX','$textY' "'"${btext[m]}"'"' \
	                    "$thumbPic2" || error_out
          		fi
       		fi
       		let navy+=$MFONTSIZE+10
    	done

#
# Last not least: Create the VMGM- and Resume-Button
#
		btexte="$TEXT_RETURN DVD-$TEXT_MENU"
		[ $info -eq 1 ] && btexte="$btexte Info-Panel"
		[ $audio -eq 1 ]&& btexte="$btexte Audio-$TEXT_MENU"
    	let navy=tvY-50
        for text in $btexte; do
			let textY=$navy+$MFONTSIZE+5
   			let shadowY=$textY+1
      		let polyY1=$textY-$MFONTSIZE+3
      		let polyY3=$textY-3
      		let polyY2=$textY-$MFONTSIZE/2
      		let lineY=$polyY3+6
    		if [ $i -eq 0 ]; then
      			mogrify -pointsize $MFONTSIZE \
            	    	-fill $scolor -draw 'text '$shadowX','$shadowY' "'"$text"'"' \
                 		-fill $tcolor -draw 'text '$textX','$textY' "'"$text"'"' \
	              		"$thumbPic2" || error_out
			else
    			mogrify +antialias -pointsize $MFONTSIZE -fill ${color[i]} \
	    		  		-draw 'polygon '"$polyX1,$polyY1 $polyX2,$polyY2 $polyX3,$polyY3" \
  				  		-draw 'line '"$lineX1,$lineY $lineX2,$lineY" \
	          			"${maskPic2[i]}" || error_out
    		fi
       		let navy-=$MFONTSIZE+10
      	done

#
# Combine the results into one Picture
#
		menumask[i]="$workDir"/vtsm_mask_"${suffix[i]}".png
   		convert -size "$normSize" xc:transparent -density "$normDensity" -units PixelsPerInch png:- | \
   				composite -compose Over -gravity Center "${maskPic2[i]}" - "${menumask[i]}" || error_out
       	mogrify -colors 3 "${menumask[i]}" || error_out
	done
	vtsmBG="$workDir"/tmp_vtsm_bg.ppm
	composite -compose Over -gravity Center "$thumbPic2" "$menuBG" "$vtsmBG" || error_out
	mogrify -depth 8 "$vtsmBG" || error_out

#
# This is the xml to tell spumux what to do
#
	cat <<EOF > "$spuxml"
<subpictures>
   <stream>
      <spu start="0"
           image="${menumask[0]}"
           highlight="${menumask[1]}"
           select="${menumask[2]}"
           autoorder="columns" force="yes"
           autooutline="infer" outlinewidth="7" />
   </stream>
</subpictures>
EOF

#
# Create MPEG-Stream from Background-Picture and mux with buttonmasks
#
	videotrack="$workDir"/tmp_vtsm.m2v
   	menumpeg="$VTSMDIR"/vtsm"$vts"_"$mnum".mpg
    if [ "$TVNORM" == "NTSC" ]; then
    	encFrameRate="30000:1001"
        encNorm="n"
    else
    	encFrameRate="25:1"
        encNorm="p"
    fi
 	ppmtoy4m -n 10 -F "$encFrameRate" -r "$vtsmBG" | \
 			mpeg2enc -a 2 -n "$encNorm" -f 8 -o "$videotrack" || error_out
 	mplex -f 8 -o /dev/stdout "$videotrack" "$audiotrack" | \
   			spumux -v4 "$spuxml" > "$menumpeg" || error_out
 	echo -e "\t\t\t</pgc>" >> "$XMLFILE"
 	echo "Menu #$mnum created"
 	let mnum+=1
done

#
# Ok, work finished. Hope everything is ok. Remove the working directory
#
rm -R "$workDir"

exit 0
