Demo 2 of 2 in category CubosLocos
 |
# solar.tcl
#
# Original C++ code by Katja Treiber and Matthias Schmidt.
# See www.cuboslocos.com for the original files.
#
# Modified for Tcl3D by Paul Obermeier 2009/06/10.
# 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 [after idle 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
Update [viewer elapsedTime]
}
$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: CubosLocos tutorial SolarSystem"
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.
#
# Factor for speed of whole animation
set ANIMATION_SPEED 2.0
set gUniqueLightNumber 0
namespace eval CuloGeode {
variable m_Material
proc new {} {
clearMaterial
}
proc clearMaterial {} {
variable m_Material
set m_Material [osg::Material]
}
proc prepareMaterial { givenMaterial } {
variable m_Material
set m_Material $givenMaterial
}
proc createTexture { texName texRepeat } {
# load texture file
set img [osgDB::readImageFile $texName]
if { $img eq "NULL" } {
puts "Error reading texture $texName"
return "NULL"
}
# create texture
osg::Texture2D texture
texture setDataVariance $::osg::Object_DYNAMIC
texture setFilter $::osg::Texture_MIN_FILTER $::osg::Texture_LINEAR_MIPMAP_LINEAR
texture setFilter $::osg::Texture_MAG_FILTER $::osg::Texture_LINEAR
# handle repeat
if { $texRepeat } {
texture setWrap $::osg::Texture_WRAP_S $::osg::Texture_REPEAT
texture setWrap $::osg::Texture_WRAP_T $::osg::Texture_REPEAT
} else {
texture setWrap $::osg::Texture_WRAP_S $::osg::Texture_CLAMP
texture setWrap $::osg::Texture_WRAP_T $::osg::Texture_CLAMP
}
texture setImage $img
return texture
}
proc createSphere { size texName texRepeat } {
variable m_Material
set sphere [osg::Geode]
$sphere addDrawable [osg::ShapeDrawable dr [osg::Sphere sp [osg::Vec3 v 0 0 4] $size]]
# assign the material to the sphere
set sphereStateSet [$sphere getOrCreateStateSet]
$sphereStateSet ref
$sphereStateSet setAttribute $m_Material osg::StateAttribute_ON
if { [string length $texName] > 0 } {
$sphereStateSet setTextureAttributeAndModes 0 \
[createTexture $texName $texRepeat] $::osg::StateAttribute_ON
}
set sphereTransform [osg::PositionAttitudeTransform]
$sphereTransform addChild $sphere
return $sphereTransform
}
proc createPlane {size texName texRepeat } {
variable m_Material
# vertex array
osg::Vec3Array vertexArray
set negSize [expr -1.0 * $size]
vertexArray push [osg::Vec3 v1 $negSize $negSize 0]
vertexArray push [osg::Vec3 v2 $size $negSize 0]
vertexArray push [osg::Vec3 v3 $size $size 0]
vertexArray push [osg::Vec3 v4 $negSize $size 0]
# face array
osg::DrawElementsUInt faceArray $::osg::PrimitiveSet_TRIANGLES 0
faceArray push 0 ; # face 1
faceArray push 1
faceArray push 2
faceArray push 2 ; # face 2
faceArray push 3
faceArray push 0
# normal array
osg::Vec3Array normalArray
normalArray push [osg::Vec3 na 0 0 1]
# normal index
osg::UIntArray normalIndexArray
normalIndexArray push 0
normalIndexArray push 0
normalIndexArray push 0
normalIndexArray push 0
# texture coordinates
osg::Vec2Array texCoords
texCoords push [osg::Vec2 tc1 0.0 0.0]
texCoords push [osg::Vec2 tc2 4.0 0.0]
texCoords push [osg::Vec2 tc3 4.0 4.0]
texCoords push [osg::Vec2 tc4 0.0 4.0]
set geometry [osg::Geometry]
$geometry setVertexArray vertexArray
$geometry setNormalArray normalArray
#$geometry setNormalIndices normalIndexArray
$geometry setNormalBinding $::osg::Geometry_BIND_PER_VERTEX
$geometry setTexCoordArray 0 texCoords
$geometry addPrimitiveSet faceArray
set plane [osg::Geode]
$plane addDrawable $geometry
# assign the material to the sphere
set planeStateSet [$plane getOrCreateStateSet]
$planeStateSet ref
$planeStateSet setAttribute $m_Material osg::StateAttribute_ON
if { [string length $texName] > 0 } {
$planeStateSet setTextureAttributeAndModes 0 \
[createTexture $texName $texRepeat] $::osg::StateAttribute_ON
}
set planeTransform [osg::PositionAttitudeTransform]
$planeTransform addChild $plane
return $planeTransform
}
}
proc createLight { color } {
global gUniqueLightNumber
osg::Light light
# each light must have a unique number
light setLightNum $gUniqueLightNumber
incr gUniqueLightNumber
# we set the light's position via a PositionAttitudeTransform object
light setPosition [osg::Vec4 lpos 0.0 0.0 0.0 1.0]
light setDiffuse $color
light setSpecular [osg::Vec4 lspec 1.0 1.0 1.0 1.0]
light setAmbient [osg::Vec4 lamb 0.0 0.0 0.0 1.0]
return light
}
proc positionStarfieldBox {} {
global gStarfield
set DISTANCE 20000
set SCALE 200
osg::Quat rotate
# top
$gStarfield(0) setPosition [osg::Vec3d pos0 0 0 $DISTANCE]
$gStarfield(0) setScale [osg::Vec3d scl0 $SCALE $SCALE 0]
# bottom
$gStarfield(1) setPosition [osg::Vec3d pos1 0 0 [expr -1.0 *$DISTANCE]]
$gStarfield(1) setScale [osg::Vec3d scl1 $SCALE $SCALE 0]
# left
rotate makeRotate [tcl3dDegToRad 90.0] 0 1 0
$gStarfield(2) setAttitude rotate
$gStarfield(2) setPosition [osg::Vec3d pos2 [expr -1.0 * $DISTANCE] 0 0]
$gStarfield(2) setScale [osg::Vec3d scl2 $SCALE $SCALE 0]
# right
rotate makeRotate [tcl3dDegToRad 90.0] 0 1 0
$gStarfield(3) setAttitude rotate
$gStarfield(3) setPosition [osg::Vec3d pos3 $DISTANCE 0 0]
$gStarfield(3) setScale [osg::Vec3d scl3 $SCALE $SCALE 0]
# front
rotate makeRotate [tcl3dDegToRad 90.0] 1 0 0
$gStarfield(4) setAttitude rotate
$gStarfield(4) setPosition [osg::Vec3d pos4 0 [expr -1.0 *$DISTANCE] 0]
$gStarfield(4) setScale [osg::Vec3d scl4 $SCALE $SCALE 0]
# back
rotate makeRotate [tcl3dDegToRad 90.0] 1 0 0
$gStarfield(5) setAttitude rotate
$gStarfield(5) setPosition [osg::Vec3d pos5 0 $DISTANCE 0]
$gStarfield(5) setScale [osg::Vec3d scl5 $SCALE $SCALE 0]
}
proc Startup {} {
global gStarfield gPlanets
global gDemo
# we need the scene's state set to enable the light for the entire scene
osg::Group scene
set lightStateSet [scene getOrCreateStateSet]
$lightStateSet ref
# create a light
osg::LightSource lightSource
lightSource setLight [createLight [osg::Vec4 lgt 0.9 0.9 0.9 1.0]]
# enable the light for the entire scene
lightSource setLocalStateSetModes $::osg::StateAttribute_ON
lightSource setStateSetModes $lightStateSet $::osg::StateAttribute_ON
osg::PositionAttitudeTransform lightTransform
lightTransform addChild lightSource
lightTransform setPosition [osg::Vec3d lt 3 0 0]
# create Geometry with CuLo-Geo
CuloGeode::new
# stars / starfield
osg::Material material
material setEmission $::osg::Material_FRONT [osg::Vec4 matEmis 1.0 1.0 1.0 1.0]
material setAmbient $::osg::Material_FRONT [osg::Vec4 matAmb 1.0 1.0 1.0 1.0]
material setShininess $::osg::Material_FRONT 25.0
CuloGeode::prepareMaterial material
for { set i 0 } { $i < 6 } { incr i } {
set gStarfield($i) [CuloGeode::createPlane 100.0 [file join $gDemo(scriptDir) "Data/stars.rgb"] true]
scene addChild $gStarfield($i)
}
# sun
CuloGeode::prepareMaterial material
set sunFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/sunmap.rgb"]]
set gPlanets(sun) [CuloGeode::createSphere 300 $sunFile false]
# planets
osg::Material material2
material2 setEmission $::osg::Material_FRONT [osg::Vec4 me 0.1 0.1 0.1 1.0]
CuloGeode::prepareMaterial material2
set mercuryFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/mercurymap.rgb"]]
set venusFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/venusmap.rgb"]]
set earthFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/earthmap1k.rgb"]]
set emoonFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/moonmap1k.rgb"]]
set marsFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/mars_1k_color.rgb"]]
set jupiterFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/jupitermap.rgb"]]
set saturnFile [tcl3dGetExtFile [file join $gDemo(scriptDir) "Data/saturnmap.rgb"]]
set gPlanets(mercury) [CuloGeode::createSphere 3.8 $mercuryFile false]
set gPlanets(venus) [CuloGeode::createSphere 9.5 $venusFile false]
set gPlanets(earth) [CuloGeode::createSphere 10 $earthFile false]
set gPlanets(emoon) [CuloGeode::createSphere 2 $emoonFile false]
set gPlanets(mars) [CuloGeode::createSphere 5.3 $marsFile false]
set gPlanets(jupiter) [CuloGeode::createSphere 109 $jupiterFile false]
set gPlanets(saturn) [CuloGeode::createSphere 91 $saturnFile false]
lightTransform addChild $gPlanets(sun)
scene addChild lightTransform
scene addChild $gPlanets(mercury)
scene addChild $gPlanets(venus)
$gPlanets(earth) addChild $gPlanets(emoon)
scene addChild $gPlanets(earth)
scene addChild $gPlanets(mars)
scene addChild $gPlanets(jupiter)
scene addChild $gPlanets(saturn)
return scene
}
proc Update { t } {
global gPlanets
set t [expr $t * $::ANIMATION_SPEED]
set SUN_DISTANCE 1500
set BASE_PERIOD [expr -1.0 * $t / 50]
set BASE_ROTATION [expr $t / 2]
osg::Quat rotate
rotate makeRotate [expr -1.0 * $t/100] 0 0 1
$gPlanets(sun) setAttitude rotate
rotate makeRotate [expr $BASE_ROTATION / 58] 0 0 1
$gPlanets(mercury) setAttitude rotate
set sin [expr sin ($BASE_PERIOD / 0.24)]
set cos [expr cos ($BASE_PERIOD / 0.24)]
set pos [[osg::Vec3d mercury $sin $cos 0] mul [expr $SUN_DISTANCE * 0.38]]
$gPlanets(mercury) setPosition $pos
rotate makeRotate [expr $BASE_ROTATION / -243] 0 0 1
$gPlanets(venus) setAttitude rotate
set sin [expr sin ($BASE_PERIOD / 0.61)]
set cos [expr cos ($BASE_PERIOD / 0.61)]
set pos [[osg::Vec3d venus $sin $cos 0] mul [expr $SUN_DISTANCE * 0.72]]
$gPlanets(venus) setPosition $pos
rotate makeRotate $BASE_ROTATION 0 0 1
$gPlanets(earth) setAttitude rotate
set pos [[osg::Vec3d earth [expr sin($BASE_PERIOD)] [expr cos($BASE_PERIOD)] 0] mul $SUN_DISTANCE]
$gPlanets(earth) setPosition $pos
set pos [[osg::Vec3d emoon [expr -sin($t)] [expr cos($t)] 0] mul 20]
$gPlanets(emoon) setPosition $pos
rotate makeRotate [expr $BASE_ROTATION / 1.02] 0 0 1
$gPlanets(mars) setAttitude rotate
set sin [expr sin ($BASE_PERIOD / 1.88)]
set cos [expr cos ($BASE_PERIOD / 1.88)]
set pos [[osg::Vec3d mars $sin $cos 0] mul [expr $SUN_DISTANCE * 1.52]]
$gPlanets(mars) setPosition $pos
rotate makeRotate [expr $BASE_ROTATION / 0.41] 0 0 1
$gPlanets(jupiter) setAttitude rotate
set sin [expr sin ($BASE_PERIOD / 11.86)]
set cos [expr cos ($BASE_PERIOD / 11.86)]
set pos [[osg::Vec3d jupiter $sin $cos 0] mul [expr $SUN_DISTANCE * 5.20]]
$gPlanets(jupiter) setPosition $pos
rotate makeRotate [expr $BASE_ROTATION / 0.44] 0 0 1
$gPlanets(saturn) setAttitude rotate
set sin [expr sin ($BASE_PERIOD / 29.44)]
set cos [expr cos ($BASE_PERIOD / 29.44)]
set pos [[osg::Vec3d saturn $sin $cos 0] mul [expr $SUN_DISTANCE * 9.53]]
$gPlanets(saturn) setPosition $pos
}
# Create the viewer and the Tk widgets.
osgViewer::ViewerRef viewer [osgViewer::Viewer]
# set the scene-graph data the viewer will render
Startup
viewer setSceneData scene
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 realize
positionStarfieldBox
while { ! [viewer done] } {
viewer frame
Update [viewer elapsedTime]
}
exit 0
}
# Use the OSG viewer inside a Togl widget.
set osgwin [viewer setUpViewerAsEmbeddedInWindow 50 50 500 400]
tcl3dOsgSetOsgWin $osgwin
viewer realize
positionStarfieldBox
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
}
|
