Demo 3 of 3 in category QuickStartGuide
 |
# OpenSceneGraph Quick Start Guide
# http://www.skew-matrix.com/OSGQSG
#
# Picking Example, Using the osgUtil Intersection classes and osgGA NodeKit
#
# Code derived from an OSG example. Original comment block follows.
#
# C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
#
# Simple example of use of osgViewer::GraphicsWindow + SimpleViewer
# that provides the user with control over view position with basic picking.
#
# Modified for Tcl3D by Paul Obermeier 2009/03/20.
# See www.tcl3d.org for the Tcl3D extension.
package require tcl3d
if { ! [tcl3dHaveOsg] } {
tk_messageBox -icon error -type ok -title "Missing Tcl3D module" \
-message "Demo needs the tcl3dOSG module."
proc Cleanup {} {}
exit 1
return
}
# Font to be used in the Tk listbox.
set gDemo(listFont) {-family {Courier} -size 10}
# Window size.
set gDemo(winWidth) 640
set gDemo(winHeight) 480
# Determine the directory and filename of this script.
set gDemo(scriptFile) [info script]
set gDemo(scriptDir) [file dirname $gDemo(scriptFile)]
# Show errors occuring in the Togl callbacks.
proc bgerror { msg } {
puts "Error: $msg\n\n$::errorInfo"
tk_messageBox -icon error -type ok -message "Error: $msg\n\n$::errorInfo"
ExitProg
}
# Print info message into widget a the bottom of the window.
proc PrintInfo { msg } {
if { [winfo exists .fr.info] } {
.fr.info configure -text $msg
}
}
# Idle callback to redisplay the scene.
proc Animate {} {
.fr.toglwin postredisplay
set ::animateId [tcl3dAfterIdle Animate]
}
proc StartAnimation {} {
if { ! [info exists ::animateId] } {
Animate
}
}
proc StopAnimation {} {
if { [info exists ::animateId] } {
after cancel $::animateId
unset ::animateId
}
}
proc CreateCallback { toglwin } {
}
proc ReshapeCallback { toglwin { w -1 } { h -1 } } {
global gDemo
set w [$toglwin width]
set h [$toglwin height]
# Propagate resize event to embedded OSG window.
tcl3dOsgWindowResize $toglwin [tcl3dOsgGetOsgWin] $w $h
set gDemo(winWidth) $w
set gDemo(winHeight) $h
}
proc DisplayCallback { toglwin } {
if { [viewer valid] } {
viewer frame
}
$toglwin swapbuffers
}
proc Cleanup {} {
uplevel #0 unset gDemo
viewer -delete
}
proc ExitProg {} {
exit
}
proc SaveOsgToFile {} {
global gDemo
set osgRoot [viewer getSceneData]
set outFile [format "%s.osgt" [file rootname $gDemo(scriptFile)]]
# Create a name on the file system, if running from within a Starpack.
set outFile [tcl3dGenExtName $outFile]
puts "Saving scenegraph to file $outFile"
if { ! [osgDB::writeNodeFile $osgRoot $outFile] } {
puts "Failed to write scenegraph to file $outFile"
}
}
proc SetMousePos { x y } {
global gDemo
set gDemo(mx) $x
set gDemo(my) $y
}
proc getXnormalized { x } {
global gDemo
return [expr {2.0*$x/$gDemo(winWidth)-1.0}]
}
proc getYnormalized { y } {
global gDemo
return [expr {2.0*$y/$gDemo(winHeight)-1.0}]
}
proc HandlePick { x y } {
global gDemo
if { $gDemo(mx) == $x && $gDemo(my) == $y } {
# If the mouse hasn't moved since the last
# button press or move event, perform a
# pick. (Otherwise, the trackball
# manipulator will handle it.)
Pick [getXnormalized $x] [getYnormalized $y]
}
}
proc SetPickBindings { toglwin osgwin } {
bind $toglwin <<LeftMousePress>> "+SetMousePos %x %y"
bind $toglwin <<LeftMouseRelease>> "+HandlePick %x %y"
}
proc CreateWidgets { osgwin } {
global gDemo
frame .fr
pack .fr -expand 1 -fill both
set toglwin .fr.toglwin
togl $toglwin -width $gDemo(winWidth) -height $gDemo(winHeight) \
-double true -depth true -alpha true \
-createcommand CreateCallback \
-reshapecommand ReshapeCallback \
-displaycommand DisplayCallback
listbox .fr.usage -font $gDemo(listFont) -height 3
label .fr.info
grid $toglwin -row 0 -column 0 -sticky news
grid .fr.usage -row 1 -column 0 -sticky news
grid .fr.info -row 2 -column 0 -sticky news
grid rowconfigure .fr 0 -weight 1
grid columnconfigure .fr 0 -weight 1
wm title . "Tcl3D demo: OSG QuickStartGuide example Picking"
wm protocol . WM_DELETE_WINDOW "ExitProg"
bind . <Key-Escape> "ExitProg"
bind . <Key-f> "SaveOsgToFile"
# Propagate key and mouse events to embedded OSG window.
bind . <KeyPress> "tcl3dOsgKeyPress $toglwin $osgwin %N"
tcl3dOsgAddTrackballBindings $toglwin $osgwin
SetPickBindings $toglwin $osgwin
.fr.usage insert end "Key-Escape Exit"
.fr.usage insert end "Key-f Save SceneGraph to file"
.fr.usage insert end "Mouse Trackball"
.fr.usage configure -state disabled
}
#
# Start of tutorial specific code.
#
# Derive a class from NodeCallback to manipulate a MatrixTransform object's matrix.
proc RotateCB { node args } {
global gAngle
if { ! [info exists gAngle] } {
set gAngle 0.0
}
osg::Matrix m
m makeRotate $gAngle [osg::Vec3 rot 0 0 1]
$node setMatrix m
# Increment the angle for the next frame.
set gAngle [expr {$gAngle + 0.01}]
}
# Create the scene graph. This is a Group root node with two
# MatrixTransform children, which multiply parent a single
# Geode loaded from the cow.osg model file.
proc CreateScene {} {
global gDemo
# Load the cow model.
set osgFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data" "cow.osg"]]
osg::NodeRef cow [osgDB::readNodeFile $osgFile]
if { ! [cow valid] } {
error "Unable to load data file. Exiting."
}
# Data variance is STATIC because we won't modify it.
cow setDataVariance $::osg::Object_STATIC
# Create a MatrixTransform to display the cow on the left.
osg::MatrixTransform mtLeft
mtLeft setName "Left Cow"
mtLeft setDataVariance $::osg::Object_STATIC
osg::Matrix m
m makeTranslate -6.0 0.0 0.0
mtLeft setMatrix m
osg::MatrixTransform mtl
mtl setName "Left Rotation"
mtl setDataVariance $::osg::Object_STATIC
m makeIdentity
mtl setMatrix m
mtLeft addChild mtl
mtl addChild [cow get]
# Create a MatrixTransform to display the cow on the right.
osg::MatrixTransform mtRight
mtRight setName "Right Cow"
mtRight setDataVariance $::osg::Object_STATIC
m makeTranslate 6 0 0
mtRight setMatrix m
osg::MatrixTransform mtr
mtr setName "Right Rotation"
mtr setDataVariance $::osg::Object_STATIC
m makeIdentity
mtr setMatrix m
mtRight addChild mtr
mtr addChild [cow get]
# Create the Group root node.
osg::Group root
root setName "Root Node"
# Data variance is STATIC because we won't modify it.
root setDataVariance $::osg::Object_STATIC
root addChild mtLeft
root addChild mtRight
return root
}
# Perform a pick operation.
proc Pick { x y } {
global gSelectedNode gCounter
if { [viewer getSceneData] eq "NULL" } {
# Nothing to pick.
return false
}
if { ! [info exists gCounter] } {
set gCounter 0
} else {
incr gCounter
}
set w 0.05
set h 0.05
set osgMajorVersion [lindex [split [tcl3dOsgGetVersion] "."] 0]
if { $osgMajorVersion >= 3 } {
set pickerId [osgUtil::LineSegmentIntersector osgUtilPicker_$gCounter \
$::osgUtil::Intersector_PROJECTION $x $y]
} else {
set pickerId [osgUtil::PolytopeIntersector osgUtilPicker_$gCounter \
$::osgUtil::Intersector_PROJECTION \
[expr {$x-$w}] [expr {$y-$h}] [expr {$x+$w}] [expr {$y+$h}]]
}
osgUtil::IntersectionVisitor iv $pickerId
set cam [viewer getCamera]
osg::Camera_accept $cam iv
if { [$pickerId containsIntersections] } {
set firstIsect [$pickerId getFirstIntersection]
set nodePath [$firstIsect cget -nodePath]
set idx [$nodePath size]
incr idx -1
while { $idx >= 0 } {
# Find the LAST MatrixTransform in the node
# path; this will be the MatrixTransform
# to attach our callback to.
set node [osg::NodeStdVec_get $nodePath $idx]
set mt [$node asMatrixTransform]
if { $mt eq "NULL" } {
incr idx -1
continue
}
# If we get here, we just found a
# MatrixTransform in the nodePath.
if { $gSelectedNode ne "" } {
# Clear the previous selected node's
# callback to make it stop spinning.
$gSelectedNode setUpdateCallback "NULL"
}
set gSelectedNode $mt
# Define the update callback procedure.
osg::tcl3dOsgNodeCallback ncRot_$gCounter RotateCB
$gSelectedNode setUpdateCallback ncRot_$gCounter
break
}
if { $gSelectedNode eq "" } {
puts "Pick failed."
}
} elseif { $gSelectedNode ne "" } {
$gSelectedNode setUpdateCallback "NULL"
}
iv -delete
$pickerId -delete
if { $gSelectedNode ne "" } {
return true
} else {
return false
}
}
set gSelectedNode ""
# Create the viewer and set its scene data to our scene
# graph created above.
osgViewer::ViewerRef viewer [osgViewer::Viewer]
viewer setSceneData [CreateScene]
if { [viewer getSceneData] eq "NULL" } {
error "No scene data available"
}
# Set the clear color to something other than chalky blue.
set cam [viewer getCamera]
osg::Camera_setClearColor $cam [osg::Vec4 col 1 1 1 1]
viewer setCameraManipulator [osgGA::TrackballManipulator]
if { $argc >= 1 && [lindex $argv 0] eq "-viewer" } {
# Only use the standard OSG viewer window without any Tk widgets.
# In this mode, picking is not implemented.
puts "Picking not implemented in osgViewer mode."
viewer setUpViewInWindow 50 50 500 400
viewer run
exit 0
}
# Use the OSG viewer inside a Togl widget.
set osgwin [viewer setUpViewerAsEmbeddedInWindow 50 50 500 400]
tcl3dOsgSetOsgWin $osgwin
viewer realize
CreateWidgets $osgwin
PrintInfo [tcl3dOsgGetInfoString]
if { [file tail [info script]] eq [file tail $::argv0] } {
# If started directly from tclsh or wish, then start animation.
update
StartAnimation
}
|
