Demo NPS03_TexturedGeometry
Demo 2 of 9 in category NPS-Tutorials
  | 
# NPS03_TexturedGeometry.tcl 
# 
# Original C++ code by Joseph Sullivan. 
# See http://www.openscenegraph.org/projects/osg/wiki/Support/Tutorials 
# for the original files. 
# 
# 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 } } { 
    set w [$toglwin width] 
    set h [$toglwin height] 
 
    # Propagate resize event to embedded OSG window. 
    tcl3dOsgWindowResize $toglwin [tcl3dOsgGetOsgWin] $w $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 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: Sullivan's OSG tutorial #3 (TexturedGeometry)" 
 
    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 
 
    .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. 
# 
 
proc createPyramid {} { 
   osg::Geode    pyramidGeode 
   osg::Geometry pyramidGeometry 
 
   pyramidGeode addDrawable pyramidGeometry 
 
   # Specify the vertices 
   osg::Vec3Array pyramidVertices 
   pyramidVertices push [osg::Vec3 p1 0 0 0] ; # front left  
   pyramidVertices push [osg::Vec3 p2 2 0 0] ; # front right  
   pyramidVertices push [osg::Vec3 p3 2 2 0] ; # back right  
   pyramidVertices push [osg::Vec3 p4 0 2 0] ; # back left  
   pyramidVertices push [osg::Vec3 p5 1 1 2] ; # peak 
    
   # Associate this set of vertices with the geometry associated with the 
   # geode we added to the scene. 
   pyramidGeometry setVertexArray pyramidVertices 
 
   osg::DrawElementsUInt pyramidBase $::osg::PrimitiveSet_QUADS 0 
   pyramidBase push 3 
   pyramidBase push 2 
   pyramidBase push 1 
   pyramidBase push 0 
   pyramidGeometry addPrimitiveSet pyramidBase 
 
   # Repeat the same for each of the four sides. Again, vertices are  
   # specified in counter-clockwise order.  
 
    osg::DrawElementsUInt pyramidFaceOne $::osg::PrimitiveSet_TRIANGLES 0 
    pyramidFaceOne push 0 
    pyramidFaceOne push 1 
    pyramidFaceOne push 4 
    pyramidGeometry addPrimitiveSet pyramidFaceOne 
 
    osg::DrawElementsUInt pyramidFaceTwo $::osg::PrimitiveSet_TRIANGLES 0 
    pyramidFaceTwo push 1 
    pyramidFaceTwo push 2 
    pyramidFaceTwo push 4 
    pyramidGeometry addPrimitiveSet pyramidFaceTwo 
 
    osg::DrawElementsUInt pyramidFaceThree $::osg::PrimitiveSet_TRIANGLES 0 
    pyramidFaceThree push 2 
    pyramidFaceThree push 3 
    pyramidFaceThree push 4 
    pyramidGeometry addPrimitiveSet pyramidFaceThree 
 
    osg::DrawElementsUInt pyramidFaceFour $::osg::PrimitiveSet_TRIANGLES 0 
    pyramidFaceFour push 3 
    pyramidFaceFour push 0 
    pyramidFaceFour push 4 
    pyramidGeometry addPrimitiveSet pyramidFaceFour 
 
    osg::Vec4Array colors 
    colors push [osg::Vec4f col1 1.0 0.0 0.0 1.0] ; # index 0 red 
    colors push [osg::Vec4f col2 0.0 1.0 0.0 1.0] ; # index 1 green 
    colors push [osg::Vec4f col3 0.0 0.0 1.0 1.0] ; # index 2 blue 
    colors push [osg::Vec4f col4 1.0 1.0 1.0 1.0] ; # index 3 white 
    colors setBinding $::osg::Geometry_BIND_PER_VERTEX 
 
    pyramidGeometry setColorArray   colors 
 
    # Since the mapping from vertices to texture coordinates is 1:1,  
    # we don't need to use an index array to map vertices to texture 
    # coordinates. We can do it directly with the 'setTexCoordArray'  
    # method of the Geometry class.  
    # This method takes a variable that is an array of two dimensional 
    # vectors (osg::Vec2). This variable needs to have the same 
    # number of elements as our Geometry has vertices. Each array element 
    # defines the texture coordinate for the cooresponding vertex in the 
    # vertex array. 
    osg::Vec2Array texcoords 5 
    texcoords set 0 [osg::Vec2 v1 0.00 0.0] ; # tex coord for vertex 0 
    texcoords set 1 [osg::Vec2 v2 0.25 0.0] ; # tex coord for vertex 1 
    texcoords set 2 [osg::Vec2 v3 0.50 0.0] ; #  "" 
    texcoords set 3 [osg::Vec2 v4 0.75 0.0] ; #  "" 
    texcoords set 4 [osg::Vec2 v5 0.50 1.0] ; #  "" 
 
    pyramidGeometry setTexCoordArray 0 texcoords 
    return pyramidGeode 
} 
 
# We have the geometry ready. Now create the viewer and the Tk widgets. 
osgViewer::ViewerRef viewer [osgViewer::Viewer] 
 
# Declare a group to act as root node of a scene. 
osg::Group root 
 
set pyramidGeode [createPyramid] 
 
root addChild $pyramidGeode 
 
osg::Texture2D KLN89FaceTexture 
# protect from being optimized away as static state: 
KLN89FaceTexture setDataVariance $::osg::Object_DYNAMIC 
 
# load an image by reading a file. 
set imgFile [file join $::gDemo(scriptDir) "Data/Textures/KLN89FaceB.tga"] 
set klnFace [osgDB::readImageFile $imgFile] 
if { $klnFace eq "NULL" } { 
    puts " couldn't find texture, quitting." 
    exit -1 
} 
 
# Assign the texture to the image we read from file. 
KLN89FaceTexture setImage $klnFace 
 
# Create a new StateSet with default settings. 
osg::StateSet stateOne 
 
# Assign texture unit 0 of our new StateSet to the texture  
# we just created and enable the texture. 
stateOne setTextureAttributeAndModes 0 KLN89FaceTexture $::osg::StateAttribute_ON 
 
# Associate this state set with the Geode that contains the pyramid. 
$pyramidGeode setStateSet stateOne 
 
# The final step is to set up and enter a simulation loop. 
 
viewer setSceneData root 
viewer setCameraManipulator [osgGA::TrackballManipulator] 
 
if { $argc >= 1 && [lindex $argv 0] eq "-viewer" } { 
    # Only use the standard OSG viewer window without any Tk widgets. 
    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 
} 
 | 
