#!/bin/sh
#                    R T W I Z A R D . T C L
# BRL-CAD
#
# Copyright (c) 2006-2012 United States Government as represented by
# the U.S. Army Research Laboratory.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# version 2.1 as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this file; see the file named COPYING for more
# information.
#
###
#
# Start-up script for both the command line and graphical modes of
# rtwizard
#

# The trailing backslash forces tcl to skip the next line \
STARTUP_HOME=`dirname $0`/..
#\
export STARTUP_HOME
# restart using btclsh \
TCLSH="btclsh"
#\
for clsh in btclsh btclsh_d ; do
# see if we're installed \
    if test -f ${STARTUP_HOME}/bin/$clsh ; then
#\
	TCLSH="${STARTUP_HOME}/bin/$clsh"
#\
	break;
#\
    fi
# see if we're not installed yet \
    if test -f ${STARTUP_HOME}/btclsh/$clsh ; then
#\
	TCLSH="${STARTUP_HOME}/btclsh/$clsh"
#\
	break;
#\
    fi
#\
done
#\
exec "$TCLSH" "$0" "$@"

#
# Begin Tcl here!
#

# We might as well populate options directly in the namespace
# where they will eventually be used.  Define that namespace
# up front.
namespace eval RtWizard {}

# Set up the options we support with rtwizard.  We will use
# an associative array named wizard_state in the RtWizard
# namespace to hold the key information - have getopt place the
# results of its parsing directly in that array
package require GetOpt
getopt::init {
        # GUI controls
        {gui 			""  	{::use_gui}}
        {no-gui 		""  	{::disable_gui}}
	# Input/output files and framebuffer servers
        {input	 		i  	{::have_gfile ::RtWizard::wizard_state(dbFile)}}
        {output   		o  	{::output ::RtWizard::wizard_state(output_filename)}}
        {fbserv-device		d  	{::fbserv_device ::RtWizard::wizard_state(fbserv_device)}}
        {fbserv-port		p  	{::fbserv_port ::RtWizard::wizard_state(fbserv_port)}}
        {width 			w	{::have_width ::RtWizard::wizard_state(width)}}
        {height 		n 	{::have_scanlines ::RtWizard::wizard_state(scanlines)}}
	# Objects to raytrace
        {color-objects		c	{::have_full_color_objs ::RtWizard::wizard_state(color_objlist) ...}}
        {ghost-objects		g	{::have_ghost_objs ::RtWizard::wizard_state(ghost_objlist) ...}}
        {line-objects		l	{::have_line_objs ::RtWizard::wizard_state(line_objlist) ...}}
	# Settings
        {background-color 	C 	{::have_bg_color ::RtWizard::wizard_state(bg_color)}}
        {ghosting-intensity 	G	{::have_ghosting_intensity ::RtWizard::wizard_state(ghosting_intensity)}}
        {line-color		""	{::have_line_color ::RtWizard::wizard_state(e_color)}}
        {non-line-color 	"" 	{::have_non_line_color ::RtWizard::wizard_state(ne_color)}}
        {occlusion 		O 	{::have_occlusion_mode ::RtWizard::wizard_state(occmode)}}
	# Image type
        {type 			t 	{::have_picture_type ::RtWizard::wizard_state(picture_type)}}
	# View
        {azimuth 		a  	{::have_azimuth ::RtWizard::wizard_state(init_azimuth)}}
        {elevation 		e 	{::have_elevation ::RtWizard::wizard_state(init_elevation)}}
        {twist 			"" 	{::have_twist ::RtWizard::wizard_state(init_twist)}}
	{perspective		P	{::have_perspective ::RtWizard::wizard_state(perspective)}}
        {zoom 			z 	{::have_zoom ::RtWizard::wizard_state(zoom)}}
	{center			""	{::have_center ::RtWizard::wizard_state(x_center) ::RtWizard::wizard_state(y_center) ::RtWizard::wizard_state(z_center)}}
	{viewsize		""	{::have_viewsize ::RtWizard::wizard_state(viewsize)}}
	{orientation		""	{::have_orientation ::RtWizard::wizard_state(orientation)}}
	{eye_pt			""	{::have_eye_pt ::RtWizard::wizard_state(eye_pt)}}
        # Debugging info
	{verbose		v 	{::RtWizard::wizard_state(verbose)}}
}

# Perform the actual option parsing
if {[info exists argv]} {
  set argv2 [getopt::getopt $argv]
  set argv ""
}
if {[info exists argc]} {
  set argc2 $argc
} else {
  set argc2 0
}

# If we have both gui and no-gui specified, use gui
if {[info exists ::use_gui] && [info exists ::disable_gui]} {
   puts "Warning - both -gui and -no-gui supplied - enabling gui"
   unset ::disable_gui
}

# There are three common possibilities for inputs specified without an option flag - the
# Geometry Database, the output filename and one or more full color components (i.e. the
# standard rt paradigm.)  It isn't possible to fully generalize handling of unspecified
# options, but there are a few cases we can support for convenience.

# See if any of the residual arguments after getopt identify a .g file that exists
if {[info exists argv2]} {
   set possible_incorrect_g_name 0
   set residualArgs {}
   foreach item $argv2 {
     if {[file extension $item] == ".g" && ![info exists ::RtWizard::wizard_state(dbFile)]} {
	if {[file exists $item]} {
	  set ::RtWizard::wizard_state(dbFile) $item
	} else {
	  set possible_incorrect_g_name $item
	}
     } else {
       lappend residualArgs $item
     }
   }
   if {![info exists ::RtWizard::wizard_state(dbFile)] && $possible_incorrect_g_name} {
      puts "Error: $possible_incorrect_g_name appears to specify a .g file, but file is not found."
      if {[info exists argv]} {exit}
   }
   set argv2 $residualArgs
}

# If it looks like we have a .pix or .png filename, use it for output
if {[info exists argv2]} {
   set residualArgs {}
   foreach item $argv2 {
     if {[file extension $item] == ".pix" || [file extension $item] == ".png"} {
	 if {![info exists ::RtWizard::wizard_state(output_filename)]} {
	    set ::RtWizard::wizard_state(output_filename) $item
	 } else {
	    puts "Note - $item potentially specifies an output file, but $::RtWizard::wizard_state(output_filename) is already set as the output file."
            lappend residualArgs $item
	 }
     } else {
       lappend residualArgs $item
     }
   }
   set argv2 $residualArgs
}

# If we still have something left, assume full color objects are being specified.  May be an incorrect
# assumption, but after the parsing already done they're either object names or garbage and we may as
# well fail after trying them.

if {[info exists argv2]} {
    if {[string length $argv2]} {
      if {![info exists ::RtWizard::wizard_state(color_objlist)]} {
         set ::RtWizard::wizard_state(color_objlist) {}
      }
      foreach item $argv2 {
         lappend ::RtWizard::wizard_state(color_objlist) $item
      }
    }
}

# If we have an explicit picture type, check whether we satisfy the minimum
# data input for that type.
if {[info exists ::have_picture_type] && ![info exists ::use_gui]} {
  switch $::RtWizard::wizard_state(picture_type) {
    A   -
    1	{
          if {![info exists ::RtWizard::wizard_state(color_objlist)]} {
             if ([info exists ::disable_gui]) {
               puts "Error - picture type $RtWizard::wizard_state(picture_type) specified, but no full color objects listed"
               puts "Please specify full color objects using the -c option\n"
               exit
             } else {
               set ::use_gui 1
             }
          }
        }
    B   -
    2	{
          if {![info exists ::RtWizard::wizard_state(line_objlist)]} {
             if ([info exists ::disable_gui]) {
               puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no line objects listed"
               puts "Please specify line objects using the -e option\n"
               exit
             } else {
               set ::use_gui 1
             }
          }
        }
    C   -
    D   -
    3	-
    4	{
          if {![info exists ::RtWizard::wizard_state(color_objlist)] || ![info exists ::RtWizard::wizard_state(line_objlist)]} {
            if (![info exists ::disable_gui]) {
               set ::use_gui 1
            } else {
              if {![info exists ::RtWizard::wizard_state(line_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no line objects listed"
                puts "Please specify line objects using the -e option\n"
              }
              if {![info exists ::RtWizard::wizard_state(color_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no color objects listed"
                puts "Please specify full color objects using the -c option\n"
              }
             exit
            }
          }
        }
    E   -
    5	{
          if {![info exists ::RtWizard::wizard_state(color_objlist)] || ![info exists ::RtWizard::wizard_state(ghost_objlist)]} {
            if (![info exists ::disable_gui]) {
               set ::use_gui 1
            } else {
              if {![info exists ::RtWizard::wizard_state(ghost_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no ghost objects listed"
                puts "Please specify ghost objects using the -g option\n"
              }
              if {![info exists ::RtWizard::wizard_state(color_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no color objects listed"
                puts "Please specify full color objects using the -c option\n"
              }
             exit
            }
          }
        }
    F   -
    6	{
          if {![info exists ::RtWizard::wizard_state(color_objlist)] || ![info exists ::RtWizard::wizard_state(line_objlist)] || ![info exists ::RtWizard::wizard_state(ghost_objlist)]} {
            if (![info exists ::disable_gui]) {
               set ::use_gui 1
            } else {
              if {![info exists ::RtWizard::wizard_state(ghost_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no ghost objects listed"
                puts "Please specify ghost objects using the -g option\n"
              }
              if {![info exists ::RtWizard::wizard_state(color_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no color objects listed"
                puts "Please specify full color objects using the -c option\n"
              }
              if {![info exists ::RtWizard::wizard_state(line_objlist)]} {
                puts "Error - picture type $::RtWizard::wizard_state(picture_type) specified, but no line objects listed"
                puts "Please specify line objects using the -e option\n"
              }
             exit
            }
          }
        }
    default {puts "Error - unknown picture type $::RtWizard::wizard_state(picture_type)\n"; exit}
  }
}

# We can set a lot of defaults, but not the objects to draw - if we don't have *something* specified,
# we have to go graphical.
if {![info exists ::RtWizard::wizard_state(color_objlist)] && ![info exists ::RtWizard::wizard_state(line_objlist)] && ![info exists ::RtWizard::wizard_state(ghost_objlist)]} {
   if {![info exists ::disable_gui]} {
    set ::use_gui 1
   } else {
    puts "Error - please specify one or more objects for at least one of color, ghost, or line rendering modes."
    if {[info exists argv]} {exit}
   }
}

# If we haven't been told what .g file to use, we're going to have to go graphical
if {![info exists ::RtWizard::wizard_state(dbFile)]} {
   if {![info exists ::disable_gui]} {
    set ::use_gui 1
   } else {
    puts "Error - please specify Geometry Database (.g) file."
    if {[info exists argv]} {exit}
   }
}

# OK, we've collected all the info we can from the inputs.  Make sure all the key
# variables are initialized to sane defaults.  The viewsize, eye_pt and center defaults are determined from
# the drawing of the objects into the display manager if not already specified.  If
# viewsize, orientation and eye_pt have already been specified, they are used instead of these
# defaults when these defaults would conflict with them.

# Geometry Database
if {![info exists ::RtWizard::wizard_state(dbFile)]} { set ::RtWizard::wizard_state(dbFile) "" }
# Initial orientation
if {![info exists ::RtWizard::wizard_state(init_azimuth)]} { set ::RtWizard::wizard_state(init_azimuth) 35 }
if {![info exists ::RtWizard::wizard_state(init_elevation)]} { set ::RtWizard::wizard_state(init_elevation) 25 }
if {![info exists ::RtWizard::wizard_state(init_twist)]} { set ::RtWizard::wizard_state(init_twist) 0 }
# Initial zoom
if {![info exists ::RtWizard::wizard_state(zoom)]} { set ::RtWizard::wizard_state(zoom) 1 }
# Initial perspective
if {![info exists ::RtWizard::wizard_state(perspective)]} { set ::RtWizard::wizard_state(perspective) 0 }
# Background color
if {![info exists ::RtWizard::wizard_state(bg_color)]} { set ::RtWizard::wizard_state(bg_color) {255 255 255} }
# Edge lines color
if {![info exists ::RtWizard::wizard_state(e_color)]} { set ::RtWizard::wizard_state(e_color) {0 0 0} }
# Edge not-lines color
if {![info exists ::RtWizard::wizard_state(ne_color)]} { set ::RtWizard::wizard_state(ne_color) {0 0 0} }
# Occlusion mode
if {![info exists ::RtWizard::wizard_state(occmode)]} { set ::RtWizard::wizard_state(occmode) 1 }
# Ghost intensity
if {![info exists ::RtWizard::wizard_state(ghosting_intensity)]} { set ::RtWizard::wizard_state(ghosting_intensity) 12 }
# Pix width
if {![info exists ::RtWizard::wizard_state(width)]} { set ::RtWizard::wizard_state(width) 512 }
# Pix height (number of scan lines) 
if {![info exists ::RtWizard::wizard_state(scanlines)]} { set ::RtWizard::wizard_state(scanlines) 512 }
# Color objects
if {![info exists ::RtWizard::wizard_state(color_objlist)]} { set ::RtWizard::wizard_state(color_objlist) {} }
# Edge objects
if {![info exists ::RtWizard::wizard_state(line_objlist)]} { set ::RtWizard::wizard_state(line_objlist) {} }
# Ghost objects
if {![info exists ::RtWizard::wizard_state(ghost_objlist)]} { set ::RtWizard::wizard_state(ghost_objlist) {} }

# Load the package that lets us output images
package require cadwidgets::RtImage

# Set verbosity if not already set
if {![info exists ::RtWizard::wizard_state(verbose)]} {
    set ::RtWizard::wizard_state(verbose) 0 
}

# If we're launching without enough arguments to fully specify an rtwizard 
# run or a gui run has been specifically requested, go graphical
if {[info exists ::use_gui]} {
   # Have to do these loads until we get "package require tclcad" and "package require dm" 
   # working - bwish loads them for us by default, but since rtwizard may be either
   # graphical or command line we need to start with btclsh
   if {$tcl_platform(platform) == "windows"} {
     load [file join [bu_brlcad_root "bin"] libtclcad[info sharedlibextension]]
     load [file join [bu_brlcad_root "bin"] libdm[info sharedlibextension]]
   } else {
     load [file join [bu_brlcad_root "lib"] libtclcad[info sharedlibextension]]
     load [file join [bu_brlcad_root "lib"] libdm[info sharedlibextension]]
   }
   # Now, load the actual Raytrace Wizard GUI
   package require RaytraceWizard
   if {[info exists argv]} {exit}
} else {

   if {![info exists ::RtWizard::wizard_state(output_filename)] && ![info exists ::RtWizard::wizard_state(fbserv_port)] && ![info exists ::RtWizard::wizard_state(fbserv_device)]} {
     set ::RtWizard::wizard_state(output_filename) rtwizard.pix
     if {![file exists $::RtWizard::wizard_state(output_filename)]} {
        puts "Warning - no output file or framebuffer specified - using file rtwizard.pix for output."
     }
   }
   if {[info exists ::RtWizard::wizard_state(output_filename)]} {
     if {[file exists $::RtWizard::wizard_state(output_filename)]} {
        puts "Error - cannot create output file, $::RtWizard::wizard_state(output_filename) alread exists."
        if {[info exists argv]} {exit}
     }
   }

   # Get an in-memory framebuffer, if we don't already have a type set
   if {![info exists ::RtWizard::wizard_state(fbserv_device)]} {
      set ::RtWizard::wizard_state(fbserv_device) /dev/mem
      set fbtype_specified 0
   } else {
      set fbtype_specified 1
   }

   # We need a port number for the fbserv.
   if {![info exists ::RtWizard::wizard_state(fbserv_port)]} {
      set ::RtWizard::wizard_state(fbserv_port) 0
      set port_number_specified 0
   } else {
      set port_number_specified 1
   }
   # Check whether the framebuffer already exists.  If it does, and if
   # it was specified on the command line, go with it.
   if { [catch {exec [file join [bu_brlcad_root bin] fblabel] -F $::RtWizard::wizard_state(fbserv_port) 1 1 " "} error ] } {
      catch {exec [file join [bu_brlcad_root bin] fbserv] -w $::RtWizard::wizard_state(width) -n $::RtWizard::wizard_state(scanlines) $::RtWizard::wizard_state(fbserv_port) $::RtWizard::wizard_state(fbserv_device) &} pid 
      if {[info exists pid]} {
        set fbserv_pid $pid
        # Wait a few milliseconds to make sure fbserv has completed its work and is available
        while { [catch {exec [file join [bu_brlcad_root bin] fblabel] -F $::RtWizard::wizard_state(fbserv_port) 1 1 " "} error] } {after 300}
      } else {
        if {$::RtWizard::wizard_state(verbose)} {puts "fbserv port $::RtWizard::wizard_state(fbserv_port) failed!"}
        incr ::RtWizard::wizard_state(fbserv_port)
      }
   } 

   # If we didn't have a pre-specified port number and the default didn't work, start counting up 
   if { ! $port_number_specified && ! [info exists fbserv_pid] } {
       incr ::RtWizard::wizard_state(fbserv_port)
       while { ! [catch {exec [file join [bu_brlcad_root bin] fbclear] -F $::RtWizard::wizard_state(fbserv_port) } error ] } {
             if {$::RtWizard::wizard_state(verbose)} {puts "fbserv port $::RtWizard::wizard_state(fbserv_port) is already in use."}
	     incr ::RtWizard::wizard_state(fbserv_port)
       }
      catch {exec [file join [bu_brlcad_root bin] fbserv] -w $::RtWizard::wizard_state(width) -n $::RtWizard::wizard_state(scanlines) $::RtWizard::wizard_state(fbserv_port) $::RtWizard::wizard_state(fbserv_device) &} pid
      set fbserv_pid $pid
      # Wait a few milliseconds to make sure fbserv has completed its work and is available
      while { [catch {exec [file join [bu_brlcad_root bin] fblabel] -F $::RtWizard::wizard_state(fbserv_port) 1 1 " "} error] } {after 300}
   }

   # Either we're using a specified view model, or we're deducing one based on user options
   if {[info exists ::RtWizard::wizard_state(viewsize)] && [info exists ::RtWizard::wizard_state(orientation)] && [info exists ::RtWizard::wizard_state(eye_pt)]} {
     set viewsize $::RtWizard::wizard_state(viewsize)
     set orientation [split $::RtWizard::wizard_state(orientation) " "]
     set eye_pt [split $::RtWizard::wizard_state(eye_pt) " "]
     if {[info exists ::have_azimuth]} {puts "Warning - view model explicitly set - ignoring azimuth option"}
     if {[info exists ::have_elevation]} {puts "Warning - view model explicitly set - ignoring elevation option"}
     if {[info exists ::have_twist]} {puts "Warning - view model explicitly set - ignoring twist option"}
     if {[info exists ::have_zoom]} {puts "Warning - view model explicitly set - ignoring zoom option"}
     if {[info exists ::have_center]} {puts "Warning - view model explicitly set - ignoring center option"}

   } else {
     if {[info exists ::RtWizard::wizard_state(viewsize)] || [info exists ::RtWizard::wizard_state(orientation)] || [info exists ::RtWizard::wizard_state(eye_pt)]} {
        if {! [info exists ::have_viewsize]} {puts "Error - when specifying view model directly, need viewsize"}
        if {! [info exists ::have_orientation]} {puts "Error - when specifying view model directly, need orientation"}
        if {! [info exists ::have_eye_pt]} {puts "Error - when specifying view model directly, need eye_pt"}
        if {[info exists argv]} {exit}
     }
     set db [go_open db db $::RtWizard::wizard_state(dbFile)]
     db new_view v1 nu

     if {[llength $::RtWizard::wizard_state(color_objlist)]} {
        foreach item $::RtWizard::wizard_state(color_objlist) {
	  db draw $item 
        }
     } 
     if {[llength $::RtWizard::wizard_state(line_objlist)]} {
        foreach item $::RtWizard::wizard_state(line_objlist) {
	  db draw $item 
        }
     } 
     if {[llength $::RtWizard::wizard_state(ghost_objlist)]} {
        foreach item $::RtWizard::wizard_state(ghost_objlist) {
	  db draw $item 
        }
     }

     db autoview v1
     db aet v1 $::RtWizard::wizard_state(init_azimuth) $::RtWizard::wizard_state(init_elevation) $::RtWizard::wizard_state(init_twist)
     db zoom v1 $::RtWizard::wizard_state(zoom)
     db perspective v1 $::RtWizard::wizard_state(perspective)
     if {[info exists ::RtWizard::wizard_state(x_center)] && [info exists ::RtWizard::wizard_state(y_center)] && [info exists ::RtWizard::wizard_state(z_center)]} {
        db center v1 $::RtWizard::wizard_state(x_center) $::RtWizard::wizard_state(y_center) $::RtWizard::wizard_state(z_center)
     }
     set view_info [regsub -all ";" [db get_eyemodel v1] ""]
     set vdata [split $view_info "\n"]
     set viewsize [lindex [lindex $vdata 0] 1]
     set orientation [lrange [lindex $vdata 1] 1 end]
     set eye_pt [lrange [lindex $vdata 2] 1 end]
   }

   ::cadwidgets::rtimage $::RtWizard::wizard_state(dbFile) $::RtWizard::wizard_state(fbserv_port) \
			$::RtWizard::wizard_state(width) $::RtWizard::wizard_state(scanlines) \
			$viewsize $orientation $eye_pt $::RtWizard::wizard_state(perspective) \
			$::RtWizard::wizard_state(bg_color) $::RtWizard::wizard_state(e_color) $::RtWizard::wizard_state(ne_color)\
			$::RtWizard::wizard_state(occmode) $::RtWizard::wizard_state(ghosting_intensity) \
			$::RtWizard::wizard_state(color_objlist) \
			$::RtWizard::wizard_state(ghost_objlist) \
			$::RtWizard::wizard_state(line_objlist)
		
   if {[info exists ::RtWizard::wizard_state(output_filename)]} {
      set output_generated 0
      if {[file extension $::RtWizard::wizard_state(output_filename)] == ".png"} {
         exec [file join [bu_brlcad_root bin] fb-png] -w $::RtWizard::wizard_state(width) -n $::RtWizard::wizard_state(scanlines) -F $::RtWizard::wizard_state(fbserv_port) $::RtWizard::wizard_state(output_filename)
         set output_generated 1
      }
      if {!$output_generated} {
         exec [file join [bu_brlcad_root bin] fb-pix] -w $::RtWizard::wizard_state(width) -n $::RtWizard::wizard_state(scanlines) -F $::RtWizard::wizard_state(fbserv_port) $::RtWizard::wizard_state(output_filename)
         set output_generated 1
      }

   }


   if {$::RtWizard::wizard_state(fbserv_device) == "/dev/mem"} {
       if {[info exists fbserv_pid]} {
          if {$tcl_platform(platform) == "windows"} {
	      set kill_cmd [auto_execok taskkill]
              set kill_args [list $kill_cmd "/F" "/PID" $fbserv_pid]
          } else {
	      set kill_cmd [auto_execok kill]
              set kill_args [list $kill_cmd $fbserv_pid]
          }
          if {$kill_cmd != ""} {
	      exec {*}$kill_args
          }
      }
   }
}

# Local Variables:
# mode: sh
# tab-width: 8
# sh-indentation: 4
# sh-basic-offset: 4
# indent-tabs-mode: t
# End:
# ex: shiftwidth=4 tabstop=8
