Paul Obermeier 2005/07/27
The Sierpinski demo implemented with tclogl.
TclOgl has been enhanced and renamed to Tcl3D.
This is a slightly modified version of Tetrahedron with 3dcanvas, but instead of using the 3dcanvas package, it uses hardware accelerated OpenGL calls.
See also Optimized Tetrahedron with tclogl.
An updated version (including the optimizations mentioned above) is available as part of the Tcl3D demos at [L1 ].
#!/bin/sh # The next line restarts using wish84 \ exec wish8.4 $0 ${1+"$@"} # tetra-3dc.tcl # Author: Gerard Sookahet # Date: 2004-06-18 # Description: 3D Sierpinski Tetrahedron with 3dcanvas # Modified to use OpenGL (package tclogl) # Author: Paul Obermeier # Date: 2005-06-27 package require Tk package require tclogl package require Togl catch { console show } bind all <Escape> { exit } proc About {} { set w .about catch {destroy $w} ; toplevel $w wm title $w "About this demo" message $w.msg -justify center -aspect 250 -relief sunken \ -text "tclogl demo: Sierpinski Tetrahedron\n\nGerard Sookahet, June 2004\n\nPaul Obermeier, June 2005" button $w.bquit -text OK -command {destroy .about} eval pack [winfo children $w] } proc rotX { w angle } { set ::xRotate [expr $::xRotate + $angle] $w postredisplay } proc rotY { w angle } { set ::yRotate [expr $::yRotate + $angle] $w postredisplay } proc rotZ { w angle } { set ::zRotate [expr $::zRotate + $angle] $w postredisplay } # Animation loop proc Animate { w } { rotY $w 3 rotZ $w 3 after 32 Animate $w } proc Sierpinski { w level l } { global rdepth if {$level > $rdepth} then return set i 1 foreach {x y z} $l { set p($i) "$x $y $z" incr i } set p12 [MidPoint [concat $p(1) $p(2)]] set p13 [MidPoint [concat $p(1) $p(3)]] set p14 [MidPoint [concat $p(1) $p(4)]] set p23 [MidPoint [concat $p(2) $p(3)]] set p24 [MidPoint [concat $p(2) $p(4)]] set p34 [MidPoint [concat $p(3) $p(4)]] incr level if {$level == $rdepth} then { DrawTetra $w [concat $p(1) $p(2) $p(3) $p(4)] } Sierpinski $w $level [concat $p(1) $p12 $p13 $p14] Sierpinski $w $level [concat $p(2) $p12 $p23 $p24] Sierpinski $w $level [concat $p(3) $p13 $p23 $p34] Sierpinski $w $level [concat $p(4) $p14 $p24 $p34] } proc DrawTetra { w l } { #puts "DrawTetra $l" set i 1 foreach {x y z} $l { set p($i) [list $x $y $z] incr i } glBegin GL_TRIANGLES glColor3f 1 0 0 ; # RED glVertex3fv $p(1) glVertex3fv $p(2) glVertex3fv $p(3) glColor3f 1 1 0 ; # YELLOW glVertex3fv $p(2) glVertex3fv $p(3) glVertex3fv $p(4) glColor3f 0 0 1 ; # BLUE glVertex3fv $p(1) glVertex3fv $p(3) glVertex3fv $p(4) glColor3f 0 1 0 ; # GREEN glVertex3fv $p(1) glVertex3fv $p(2) glVertex3fv $p(4) glEnd incr ::numTrias 4 } # Return the middle coordinates of two 3d points proc MidPoint { l } { set X 0 set Y 0 set Z 0 foreach {x y z} $l { set X [expr {$X + $x}] set Y [expr {$Y + $y}] set Z [expr {$Z + $z}] } return [list [expr {$X/2}] [expr {$Y/2}] [expr {$Z/2}]] } proc Init { w } { set edge 340 set x1 [expr {sqrt(3)*$edge/3}] set x2 [expr {sqrt(3)*$edge/6}] set z3 [expr {sqrt(6)*$edge/3}] set y2 [expr {$edge/2}] # Vertices' coordinates of the regular tetrahedron set p1 "$x1 0 0" set p2 "-$x2 $y2 0" set p3 "-$x2 -$y2 0" set p4 "0 0 $z3" if { [info exists ::sierList] } { glDeleteLists $::sierList 1 } set ::sierList [glGenLists 1] glNewList $::sierList GL_COMPILE set ::numTrias 0 Sierpinski $w 0 [concat $p1 $p2 $p3 $p4] puts "Number of triangles: $::numTrias" glEndList } proc tclCreateFunc { w } { glClearColor 0 0 0 0 glEnable GL_DEPTH_TEST glShadeModel GL_FLAT Init $w } proc tclDisplayFunc { w } { glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT] glPushMatrix glTranslatef 0 0 [expr -1.0 * $::vdist] glRotatef $::xRotate 1.0 0.0 0.0 glRotatef $::yRotate 0.0 1.0 0.0 glRotatef $::zRotate 0.0 0.0 1.0 glCallList $::sierList glPopMatrix $w swapbuffers } proc tclReshapeFunc { toglwin w h } { glViewport 0 0 $w $h glMatrixMode GL_PROJECTION glLoadIdentity gluPerspective 60.0 [expr double($w)/double($h)] 1.0 2000.0 glMatrixMode GL_MODELVIEW glLoadIdentity gluLookAt 0.0 0.0 5.0 0.0 0.0 0.0 0.0 1.0 0.0 } set vdist 400 set rdepth 1 set xRotate 0.0 set yRotate 0.0 set zRotate 0.0 wm title . "Sierpinski Tetrahedron" togl .c -width 500 -height 500 \ -double true -depth true \ -displayproc tclDisplayFunc \ -reshapeproc tclReshapeFunc \ -createproc tclCreateFunc pack .c -side top set f1 [frame .f1] label $f1.l1 -text "Recursive depth " spinbox $f1.sdepth -from 1 -to 10 -textvariable rdepth -width 4 label $f1.l2 -text " View distance " scale $f1.vd -from 0 -to 1000 -length 200 -orient horiz -showvalue true \ -variable vdist -command {.c postredisplay} eval pack [winfo children $f1] -side left pack $f1 set f2 [frame .f2] button $f2.brun -text "Run" -width 10 -fg white -bg blue -command {Init .c} button $f2.bromega -text "Z rotate" -width 10 -command {rotZ .c 8} button $f2.brphi -text "Y rotate" -width 10 -command {rotY .c 8} button $f2.brtheta -text "X rotate" -width 10 -command {rotX .c 8} button $f2.banim -text Animate -width 10 -command {Animate .c} button $f2.babout -text A -width 1 -bg grey -command {About} button $f2.bquit -text Quit -width 10 -bg grey -command exit eval pack [winfo children $f2] -side left pack $f2 proc handleRot {x y win} { global cx cy rotY $win [expr {180 * (double($x - $cx) / [winfo width $win])}] rotX $win [expr {180 * (double($y - $cy) / [winfo height $win])}] set cx $x set cy $y } bind .c <1> {set cx %x; set cy %y} bind .c <B1-Motion> {handleRot %x %y %W}
This is wrong:
scale $f1.vd -from 0 -to 1000 -length 200 -orient horiz -showvalue true -variable vdist -command {.c postredisplay}
Since "scale" passed in parameter to ".c postredisplay <value>" and it doesn't like that. Fix is
proc handleScale {s} { .c postredisplay } scale $f1.vd -from 0 -to 1000 -length 200 -orient horiz -showvalue true -variable vdist -command {handleScale}
Also, tclReshapeFunc callback passed in only one value. So it has to be
proc tclReshapeFunc { toglwin } { set w [$toglwin width] set h [$toglwin height]