# osgviewer.tcl: The standard OpenSceneGraph viewer in Tcl.
#
# OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
#
# This application is open source and may be redistributed and/or modified   
# freely and without restriction, both in commericial and non commercial
# applications, as long as this copyright notice is maintained.
# 
# This application 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.
#
# Original C++ code by Robert Osfield.
# See http://www.openscenegraph.org for the original files.
#
# Modified for Tcl3D by Paul Obermeier 2009/03/20.
# See www.tcl3d.org for the Tcl3D extension.

package require Tk
package require tcl3d

# Use an ArgumentParser object to manage the program arguments.

# Add the program name (i.e. Tcl script name) as first list entry
# for C/C++ main compatibility.
set argv [linsert $argv 0 $argv0]

# Don't need to specify the number of elements due to the wrapping of the C++ constructor.
osg::ArgumentParser arguments $argv

set appName [arguments getApplicationName]

set appUsage [arguments getApplicationUsage]
$appUsage setApplicationName $appName

$appUsage setDescription [format "%s is the standard OpenSceneGraph example which loads and visualises 3d models." $appName]

$appUsage setCommandLineUsage [format "%s \[options\] filename ..." $appName]
$appUsage addCommandLineOption "--image <filename>" "Load an image and render it on a quad"
$appUsage addCommandLineOption "--dem <filename>" "Load an image/DEM and render it on a HeightField"
$appUsage addCommandLineOption "-h or --help" "Display command line parameters"
$appUsage addCommandLineOption "--help-env" "Display environmental variables available"
$appUsage addCommandLineOption "--help-keys" "Display keyboard & mouse bindings available"
$appUsage addCommandLineOption "--help-all" "Display all command line, env vars and keyboard & mouse bindings."
$appUsage addCommandLineOption "--SingleThreaded" "Select SingleThreaded threading model for viewer."
$appUsage addCommandLineOption "--CullDrawThreadPerContext" "Select CullDrawThreadPerContext threading model for viewer."
$appUsage addCommandLineOption "--DrawThreadPerContext" "Select DrawThreadPerContext threading model for viewer."
$appUsage addCommandLineOption "--CullThreadPerCameraDrawThreadPerContext" "Select CullThreadPerCameraDrawThreadPerContext threading model for viewer."

# If user request help write it out to cout.
set helpAll [expr [arguments find "--help-all"] > 0]

set helpType 0
if { $helpAll || ([arguments find "-h"] > 0) || ([arguments find "--help"] > 0) } {
    set helpType $::osg::ApplicationUsage_COMMAND_LINE_OPTION
}
if { $helpAll || ([arguments find "--help-env"] > 0) } {
    set helpType [expr $helpType | $::osg::ApplicationUsage_ENVIRONMENTAL_VARIABLE]
}
if { $helpAll || ([arguments find "--help-keys"] > 0) } {
    set helpType [expr $helpType | $::osg::ApplicationUsage_KEYBOARD_MOUSE_BINDING]
}

if { $helpType } {
    puts "[$appUsage write $helpType]"
    exit 1
}

osgViewer::Viewer myviewer arguments
osgViewer::ViewerRef viewer myviewer
    
# Report any errors if they have occurred when parsing the program arguments.
if { [arguments errors] } {
    puts "[arguments writeErrorMessages]"
    exit 1
}

if { [arguments getNumArgs] <= 1 } {
    $appUsage write $::osg::ApplicationUsage_COMMAND_LINE_OPTION
    exit 1
}

# set up the camera manipulators.
osgGA::KeySwitchMatrixManipulator keyswitchManipulator

keyswitchManipulator addMatrixManipulator [tcl3dOsgKeysym 1] "Trackball" [osgGA::TrackballManipulator]
keyswitchManipulator addMatrixManipulator [tcl3dOsgKeysym 2] "Flight"    [osgGA::FlightManipulator]
keyswitchManipulator addMatrixManipulator [tcl3dOsgKeysym 3] "Drive"     [osgGA::DriveManipulator]
keyswitchManipulator addMatrixManipulator [tcl3dOsgKeysym 4] "Terrain"   [osgGA::TerrainManipulator]

set keyForAnimationPath [tcl3dOsgKeysym 5]
while { true } {
    set pos [arguments find "-p"]
    if { $pos <= 0 } {
        break
    }
    set pathfile [arguments get [expr $pos+1]]
    arguments remove $pos 2
    osgGA::AnimationPathManipulator apm_$keyForAnimationPath $pathfile
    if { [apm_$keyForAnimationPath valid] } {
        set num [keyswitchManipulator getNumMatrixManipulators]
        keyswitchManipulator addMatrixManipulator $keyForAnimationPath "Path" apm_$keyForAnimationPath
        keyswitchManipulator selectMatrixManipulator $num
        incr keyForAnimationPath
    }
}

viewer setCameraManipulator keyswitchManipulator

# add the state manipulator
set cam [viewer getCamera]
set ss  [osg::Node_getOrCreateStateSet $cam]
viewer addEventHandler [osgGA::StateSetManipulator ssm $ss]

# add the thread model handler
viewer addEventHandler [osgViewer::ThreadingHandler]

# add the window size toggle handler
viewer addEventHandler [osgViewer::WindowSizeHandler]
        
# add the stats handler
viewer addEventHandler [osgViewer::StatsHandler]

# add the help handler
viewer addEventHandler [osgViewer::HelpHandler $appUsage]

# add the record camera path handler
viewer addEventHandler [osgViewer::RecordCameraPathHandler]

# load the data
set loadedModel [osgDB::readNodeFiles arguments]
if { $loadedModel eq "NULL"} {
    puts "[arguments getApplicationName] : No data loaded"
    exit 1
}

# Any option left unread are converted into errors to write out later.
arguments reportRemainingOptionsAsUnrecognized

# Report any errors if they have occurred when parsing the program arguments.
if { [arguments errors] } {
    puts "[arguments writeErrorMessages]"
    exit 1
}

# optimize the scene graph, remove redundant nodes and state etc.
osgUtil::Optimizer optimizer
optimizer optimize $loadedModel

viewer setSceneData $loadedModel

viewer realize

viewer run

exit 0
