OUTPUT BUFFER:
# Lesson21.tcl # # NeHe's Line Tutorial # # This Code Was Created By Jeff Molofee 2000 # If You've Found This Code Useful, Please Let Me Know. # Visit My Site At nehe.gamedev.net # # Modified for Tcl3D by Paul Obermeier 2006/03/14 # See www.tcl3d.org for the Tcl3D extension. package require Img ; # Img extension for loading BMP files package require tcl3d 0.5.0 ; # Tcl3D extension for OpenGL graphics # Optional: Snack extension for playing WAV sound files set retVal [catch {package require sound} soundVersion] set gDemo(haveSnack) [expr !$retVal] # Determine the directory of this script. set gDemo(scriptDir) [file dirname [info script]] # Window size. set gDemo(winWidth) 640 set gDemo(winHeight) 480 # Display mode. set gDemo(fullScreen) 0 # Initialize administrative arrays. for { set loop1 0 } { $loop1 < 11 } { incr loop1 } { for { set loop2 0 } { $loop2 < 11 } { incr loop2 } { set vline($loop1,$loop2) 0 set hline($loop1,$loop2) 0 } } for { set loop1 0 } { $loop1 < 9 } { incr loop1 } { set enemy($loop1,x) 0 set enemy($loop1,y) 0 set enemy($loop1,fx) 0 set enemy($loop1,fy) 0 set enemy($loop1,spin) 0.0 } set hourglass(x) 0 set hourglass(y) 0 set hourglass(fx) 0 set hourglass(fy) 0 set hourglass(spin) 0.0 set player(x) 0 set player(y) 0 set player(fx) 0 set player(fy) 0 set player(spin) 0.0 set keys(LEFT) 0 set keys(RIGHT) 0 set keys(UP) 0 set keys(DOWN) 0 set keys(SPACE) 0 set gDemo(filled) 0 ; # Done Filling In The Grid? set gDemo(gameover) 0 ; # Is The Game Over? set gDemo(anti) 1 ; # Antialiasing? set gDemo(active) 1 ; # Window Active Flag Set To TRUE By Default set gDemo(delay) 0 ; # Enemy Delay set gDemo(adjust) 3 ; # Speed Adjustment For Really Slow Video Cards set gDemo(lives) 5 ; # Player Lives set gDemo(level) 1 ; # Internal Game Level set gDemo(level2) $gDemo(level) ; # Displayed Game Level set gDemo(stage) 1 ; # Game Stage set gDemo(steps) { 1 2 4 5 10 20 } ; # Stepping Values For Slow Video Adjustment set gDemo(texture) [tcl3dVector GLuint 5] ; # Font Texture Storage Space # Show errors occuring in the Togl callbacks. proc bgerror { msg } { tk_messageBox -icon error -type ok -message "Error: $msg\n\n$::errorInfo" ExitProg } proc SetFullScreenMode { win } { set sh [winfo screenheight $win] set sw [winfo screenwidth $win] wm minsize $win $sw $sh wm maxsize $win $sw $sh set fmtStr [format "%dx%d+0+0" $sw $sh] wm geometry $win $fmtStr wm overrideredirect $win 1 focus -force $win } proc SetWindowMode { win w h } { set sh [winfo screenheight $win] set sw [winfo screenwidth $win] wm minsize $win 10 10 wm maxsize $win $sw $sh set fmtStr [format "%dx%d+0+25" $w $h] wm geometry $win $fmtStr wm overrideredirect $win 0 focus -force $win } # Toggle between windowing and fullscreen mode. proc ToggleWindowMode {} { global gWidList if { $::gDemo(fullScreen) } { SetFullScreenMode . set ::gDemo(fullScreen) false set ::slowdown 2.0 } else { SetWindowMode . $::gDemo(winWidth) $::gDemo(winHeight) set ::gDemo(fullScreen) true set ::slowdown 1.0 } } proc LoadGLTextures {} { # Load texture images. set imgList { "Font.bmp" "Image.bmp" } glGenTextures [llength $imgList] $::gDemo(texture) ; # Create N Textures set imgInd 0 foreach imgName $imgList { set texName [file join $::gDemo(scriptDir) "Data" $imgName] set retVal [catch {set phImg [image create photo -file $texName]} err1] if { $retVal != 0 } { error "Error reading image $texName ($err1)" } else { set w [image width $phImg] set h [image height $phImg] set n [tcl3dPhotoChans $phImg] set TextureImage [tcl3dVectorFromPhoto $phImg] image delete $phImg } if { $n == 3 } { set type $::GL_RGB } else { set type $::GL_RGBA } glBindTexture GL_TEXTURE_2D [$::gDemo(texture) get $imgInd] glTexImage2D GL_TEXTURE_2D 0 $n $w $h 0 $type GL_UNSIGNED_BYTE $TextureImage glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR $TextureImage delete ; # Free The Texture Image Memory incr imgInd } } proc IntRand {} { return [expr {int (rand() * 32767.0)}] } proc PlaySound { wavFile blockingFlag } { global gDemo if { ! $gDemo(haveSnack) } { after 500 return } if { $wavFile eq "" } { # OPA TODO Kill Sound return } set fullName [file join $::gDemo(scriptDir) "Data" $wavFile] set fullName [tcl3dGetExtFile $fullName] set snd [snack::sound -load $fullName] $snd play -blocking $blockingFlag } # Initialize Our Timer (Get It Ready) proc TimerInit {} { set ::timer [tcl3dNewSwatch] tcl3dResetSwatch $::timer tcl3dStartSwatch $::timer } # Get Time In Milliseconds proc TimerGetTime {} { return [expr {1000.0 * [tcl3dLookupSwatch $::timer]}] } # Reset Player And Enemies proc ResetObjects {} { set ::player(x) 0 ; # Reset Player X Position To Far Left Of The Screen set ::player(y) 0 ; # Reset Player Y Position To The Top Of The Screen set ::player(fx) 0 ; # Set Fine X Position To Match set ::player(fy) 0 ; # Set Fine Y Position To Match set num [expr $::gDemo(stage) * $::gDemo(level)] for { set loop1 0 } { $loop1 < $num } { incr loop1 } { set ::enemy($loop1,x) [expr 5+[IntRand]%6] ; # Select A Random X Position set ::enemy($loop1,y) [expr [IntRand]%11] ; # Select A Random Y Position set ::enemy($loop1,fx) [expr $::enemy($loop1,x)*60] ; # Set Fine X To Match set ::enemy($loop1,fy) [expr $::enemy($loop1,y)*40] ; # Set Fine Y To Match } } # Build Our Font Display List proc BuildFont {} { set ::base [glGenLists 256] ; # Creating 256 Display Lists glBindTexture GL_TEXTURE_2D [$::gDemo(texture) get 0] ; # Select Our Font Texture for { set loop1 0 } { $loop1 < 256 } { incr loop1 } { set cx [expr double($loop1%16)/16.0] ; # X Position Of Current Character set cy [expr double($loop1/16)/16.0] ; # Y Position Of Current Character glNewList [expr $::base+$loop1] GL_COMPILE ; # Start Building A List glBegin GL_QUADS ; # Use A Quad For Each Character glTexCoord2f $cx [expr 1.0-$cy-0.0625] ; # Texture Coord (Bottom Left) glVertex2d 0 16 ; # Vertex Coord (Bottom Left) glTexCoord2f [expr $cx+0.0625] [expr 1.0-$cy-0.0625] ; # Texture Coord (Bottom Right) glVertex2i 16 16 ; # Vertex Coord (Bottom Right) glTexCoord2f [expr $cx+0.0625] [expr 1.0-$cy] ; # Texture Coord (Top Right) glVertex2i 16 0 ; # Vertex Coord (Top Right) glTexCoord2f $cx [expr 1.0-$cy] ; # Texture Coord (Top Left) glVertex2i 0 0 ; # Vertex Coord (Top Left) glEnd ; # Done Building Our Quad (Character) glTranslated 15 0 0 ; # Move To The Right Of The Character glEndList ; # Done Building The Display List } ; # Loop Until All 256 Are Built } # Delete The Font From Memory proc KillFont {} { glDeleteLists $::base 256 ; # Delete All 256 Display Lists } # Where The Printing Happens proc glPrint { x y cset fmt args } { set text [format $fmt $args] if { $cset > 1 } { # Did User Choose An Invalid Character Set? set cset 1 ; # If So, Select Set 1 (Italic) } glEnable GL_TEXTURE_2D ; # Enable Texture Mapping glLoadIdentity ; # Reset The Modelview Matrix glTranslated $x $y 0 ; # Position The Text (0,0 - Bottom Left) glListBase [expr {$::base+(128*$cset)}] ; # Choose The Font Set (0 or 1) if { $cset == 0 } { # If Set 0 Is Being Used Enlarge Font glScalef 1.5 2.0 1.0 ; # Enlarge Font Width And Height } set len [string length $text] set sa [tcl3dVectorFromString GLubyte $text] $sa addvec -32 0 $len ; # Subtract 32 (space) glCallLists $len GL_UNSIGNED_BYTE $sa ; # Write The Text To The Screen $sa delete glDisable GL_TEXTURE_2D ; # Disable Texture Mapping } # Resize And Initialize The GL Window proc ReshapeCallback { toglwin { w -1 } { h -1 } } { set w [$toglwin width] set h [$toglwin height] glViewport 0 0 $w $h ; # Reset The Current Viewport glMatrixMode GL_PROJECTION ; # Select The Projection Matrix glLoadIdentity ; # Reset The Projection Matrix glOrtho 0.0 $w $h 0.0 -1.0 1.0 ; # Create Ortho 640x480 View (0,0 At Top Left) glMatrixMode GL_MODELVIEW ; # Select The Modelview Matrix glLoadIdentity ; # Reset The Modelview Matrix set ::gDemo(winWidth) $w set ::gDemo(winHeight) $h } # All Setup For OpenGL Goes Here proc CreateCallback { toglwin } { LoadGLTextures ; # Jump To Texture Loading Routine BuildFont ; # Build The Font glShadeModel GL_SMOOTH ; # Enable Smooth Shading glClearColor 0.0 0.0 0.0 0.5 ; # Black Background glClearDepth 1.0 ; # Depth Buffer Setup glHint GL_LINE_SMOOTH_HINT GL_NICEST ; # Set Line Antialiasing glEnable GL_BLEND ; # Enable Blending glBlendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA ; # Type Of Blending To Use } proc HandleLogic {} { set step [lindex $::gDemo(steps) $::gDemo(adjust)] set num [expr {$::gDemo(stage) * $::gDemo(level)}] if { ! $::gDemo(gameover) && $::gDemo(active) } { # If Game Isn't Over And Programs Active Move Objects for { set loop1 0 } { $loop1 < $num } { incr loop1 } { if { ($::enemy($loop1,x) < $::player(x)) && \ ($::enemy($loop1,fy) == [expr {$::enemy($loop1,y)*40}]) } { incr ::enemy($loop1,x) ; # Move The Enemy Right } if { ($::enemy($loop1,x) > $::player(x)) && \ ($::enemy($loop1,fy) == [expr {$::enemy($loop1,y)*40}]) } { incr ::enemy($loop1,x) -1 ; # Move The Enemy Left } if { ($::enemy($loop1,y) < $::player(y)) && \ ($::enemy($loop1,fx) == [expr {$::enemy($loop1,x)*60}]) } { incr ::enemy($loop1,y) ; # Move The Enemy Down } if { ($::enemy($loop1,y) > $::player(y)) && \ ($::enemy($loop1,fx) == [expr {$::enemy($loop1,x)*60}]) } { incr ::enemy($loop1,y) -1 ; # Move The Enemy Up } if { ($::gDemo(delay) > [expr {3-$::gDemo(level)}]) && ($::hourglass(fx) != 2) } { # If Our Delay Is Done And Player Doesn't Have Hourglass set ::gDemo(delay) 0 ; # Reset The Delay Counter Back To Zero for { set loop2 0 } { $loop2 < $num } { incr loop2 } { if { $::enemy($loop2,fx) < [expr {$::enemy($loop2,x)*60}] } { # Is Fine Position On X Axis Lower Than Intended Position? # If So, Increase Fine Position On X Axis set ::enemy($loop2,fx) [expr {$::enemy($loop2,fx) + $step}] # Spin Enemy Clockwise set ::enemy($loop2,spin) [expr {$::enemy($loop2,spin) + $step}] } if { $::enemy($loop2,fx) > [expr {$::enemy($loop2,x)*60}] } { # Is Fine Position On X Axis Higher Than Intended Position? # If So, Decrease Fine Position On X Axis set ::enemy($loop2,fx) [expr {$::enemy($loop2,fx) - $step}] # Spin Enemy Counter Clockwise set ::enemy($loop2,spin) [expr {$::enemy($loop2,spin) - $step}] } if { $::enemy($loop2,fy) < [expr {$::enemy($loop2,y)*40}] } { # Is Fine Position On Y Axis Lower Than Intended Position? # If So, Increase Fine Position On Y Axis set ::enemy($loop2,fy) [expr {$::enemy($loop2,fy) + $step}] # Spin Enemy Clockwise set ::enemy($loop2,spin) [expr {$::enemy($loop2,spin) + $step}] } if { $::enemy($loop2,fy) > [expr {$::enemy($loop2,y)*40}] } { # Is Fine Position On Y Axis Higher Than Intended Position? # If So, Decrease Fine Position On Y Axis set ::enemy($loop2,fy) [expr {$::enemy($loop2,fy) - $step}] # Spin Enemy Counter Clockwise set ::enemy($loop2,spin) [expr {$::enemy($loop2,spin) - $step}] } } } # Are Any Of The Enemies On Top Of The Player? if { ($::enemy($loop1,fx) == $::player(fx)) && \ ($::enemy($loop1,fy) == $::player(fy)) } { incr ::gDemo(lives) -1 ; # If So, Player Loses A Life if { $::gDemo(lives) == 0 } { # Are We Out Of Lives? set ::gDemo(gameover) 1 ; # If So, gameover Becomes TRUE } ResetObjects ; # Reset Player / Enemy Positions PlaySound "Die.wav" true ; # Play The Death Sound } } if { $::keys(RIGHT) && ($::player(x) < 10) && \ ($::player(fx) == [expr {$::player(x)*60}]) && ($::player(fy) == [expr {$::player(y)*40}]) } { set ::hline($::player(x),$::player(y)) 1 ; # Mark The Current Horizontal Border As Filled incr ::player(x) ; # Move The Player Right } if { $::keys(LEFT) && ($::player(x) > 0) && \ ($::player(fx) == [expr {$::player(x)*60}]) && ($::player(fy) == [expr {$::player(y)*40}]) } { incr ::player(x) -1 ; # Move The Player Left set ::hline($::player(x),$::player(y)) 1 ; # Mark The Current Horizontal Border As Filled } if { $::keys(DOWN) && ($::player(y) < 10) && \ ($::player(fx) == [expr {$::player(x)*60}]) && ($::player(fy) == [expr {$::player(y)*40}]) } { set ::vline($::player(x),$::player(y)) 1 ; # Mark The Current Vertical Border As Filled incr ::player(y) ; # Move The Player Down } if { $::keys(UP) && ($::player(y) > 0) && \ ($::player(fx) == [expr {$::player(x)*60}]) && ($::player(fy) == [expr {$::player(y)*40}]) } { incr ::player(y) -1 ; # Move The Player Up set ::vline($::player(x),$::player(y)) 1 ; # Mark The Current Verticle Border As Filled } # Is Fine Position On X Axis Lower Than Intended Position? if { $::player(fx) < [expr {$::player(x)*60}] } { # If So, Increase The Fine X Position set ::player(fx) [expr {$::player(fx) + $step}] } # Is Fine Position On X Axis Greater Than Intended Position? if { $::player(fx) > [expr {$::player(x)*60}] } { # If So, Decrease The Fine X Position set ::player(fx) [expr {$::player(fx) - $step}] } # Is Fine Position On Y Axis Lower Than Intended Position? if { $::player(fy) < [expr {$::player(y)*40}] } { # If So, Increase The Fine Y Position set ::player(fy) [expr {$::player(fy) + $step}] } # Is Fine Position On Y Axis Greater Than Intended Position? if { $::player(fy) > [expr {$::player(y)*40}] } { # If So, Decrease The Fine Y Position set ::player(fy) [expr {$::player(fy) - $step}] } } else { if { $::keys(SPACE) } { # If Spacebar Is Being Pressed set ::gDemo(gameover) 0 ; # gameover Becomes FALSE set ::gDemo(filled) 1 ; # filled Becomes TRUE set ::gDemo(level) 1 ; # Starting Level Is Set Back To One set ::gDemo(level2) 1 ; # Displayed Level Is Also Set To One set ::gDemo(stage) 0 ; # Game Stage Is Set To Zero set ::gDemo(lives) 5 ; # Lives Is Set To Five } } if { $::gDemo(filled) } { # Is The Grid Filled In? PlaySound "Complete.wav" true ; # If So, Play The Level Complete Sound incr ::gDemo(stage) ; # Increase The Stage if { $::gDemo(stage) > 3 } { set ::gDemo(stage) 1 ; # If So, Set The Stage To One incr ::gDemo(level) ; # Increase The Level incr ::gDemo(level2) ; # Increase The Displayed Level if { $::gDemo(level) > 3 } { set ::gDemo(level) 3 ; # If So, Set The Level To 3 incr ::gDemo(lives) ; # Give The Player A Free Life if { $::gDemo(lives) > 5 } { # Does The Player Have More Than 5 Lives? set ::gDemo(lives) 5 ; # If So, Set Lives To Five } } } ResetObjects ; # Reset Player / Enemy Positions for { set loop1 0 } { $loop1 < 11 } { incr loop1 } { # Loop Through The Grid X Coordinates for { set loop2 0 } { $loop2 < 11 } { incr loop2 } { # Loop Through The Grid Y Coordinates if { $loop1 < 10 } { set ::hline($loop1,$loop2) 0 ; # Set The Current Horizontal Value To FALSE } if { $loop2 < 10 } { set ::vline($loop1,$loop2) 0 ; # Set The Current Vertical Value To FALSE } } } } # If The Player Hits The Hourglass While It's Being Displayed On The Screen if { ($::player(fx) == [expr {$::hourglass(x)*60}]) && \ ($::player(fy) == [expr {$::hourglass(y)*40}]) && ($::hourglass(fx) == 1) } { # Play Freeze Enemy Sound PlaySound "Freeze.wav" false ; # OPA TODO LOOP set ::hourglass(fx) 2 ; # Set The hourglass fx Variable To Two set ::hourglass(fy) 0 ; # Set The hourglass fy Variable To Zero } # Spin The Player Clockwise set ::player(spin) [expr {$::player(spin) + 0.5 * $step}] if { $::player(spin) > 360.0 } { set ::player(spin) [expr {$::player(spin) - 360}] } # Spin The Hourglass Counter Clockwise set ::hourglass(spin) [expr {$::hourglass(spin) - 0.25 * $step}] if { $::hourglass(spin) < 0.0 } { set ::hourglass(spin) [expr {$::hourglass(spin) + 360}] } set ::hourglass(fy) [expr {$::hourglass(fy) + $step}] if { ($::hourglass(fx) == 0) && ($::hourglass(fy) > [expr {6000/$::gDemo(level)}]) } { PlaySound "Hourglass.wav" false set ::hourglass(x) [expr [IntRand]%10+1] ; # Give The Hourglass A Random X Value set ::hourglass(y) [expr [IntRand]%11] ; # Give The Hourglass A Random Y Value set ::hourglass(fx) 1 ; # Set hourglass fx Variable To One (Hourglass Stage) set ::hourglass(fy) 0 ; # Set hourglass fy Variable To Zero (Counter) } if { ($::hourglass(fx) == 1) && ($::hourglass(fy) > [expr {6000/$::gDemo(level)}]) } { set ::hourglass(fx) 0 ; # If So, Set fx To Zero (Hourglass Will Vanish) set ::hourglass(fy) 0 ; # Set fy to Zero (Counter Is Reset) } if { ($::hourglass(fx) == 2) && ($::hourglass(fy) > [expr {500+(500*$::gDemo(level))}]) } { PlaySound "" false ; # If So, Kill The Freeze Sound set ::hourglass(fx) 0 ; # Set hourglass fx Variable To Zero set ::hourglass(fy) 0 ; # Set hourglass fy Variable To Zero } incr ::gDemo(delay) ; # Increase The Enemy Delay Counter } # Here's Where We Do All The Drawing proc DisplayCallback { toglwin } { set start [TimerGetTime] ; # Grab Timer Value Before We Draw set count 0 while {[TimerGetTime] < [expr {$start + double([lindex $::gDemo(steps) $::gDemo(adjust)])*2.0}] } { incr count ; # Waste Cycles On Fast Systems } # Clear Screen And Depth Buffer glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT] # Viewport command is not really needed, but has been inserted for # Mac OSX. Presentation framework (Tk) does not send a reshape event, # when switching from one demo to another. glViewport 0 0 [$toglwin width] [$toglwin height] glBindTexture GL_TEXTURE_2D [$::gDemo(texture) get 0] ; # Select Our Font Texture glColor3f 1.0 0.5 1.0 ; # Set Color To Purple glPrint 207 24 0 "GRID CRAZY" ; # Write GRID CRAZY On The Screen glColor3f 1.0 1.0 0.0 ; # Set Color To Yellow glPrint 20 20 1 "Level:%2i" $::gDemo(level2) ; # Write Actual Level Stats glPrint 20 40 1 "Stage:%2i" $::gDemo(stage) ; # Write Stage Stats if { $::gDemo(gameover) } { # Pick A Random Color glColor3ub [expr [IntRand]%255] [expr [IntRand]%255] [expr [IntRand]%255] glPrint 472 20 1 "GAME OVER" ; # Write GAME OVER To The Screen glPrint 456 40 1 "PRESS S" ; # Write PRESS S To The Screen } for { set loop1 0 } { $loop1 < [expr {$::gDemo(lives)-1}] } { incr loop1 } { glLoadIdentity ; # Reset The View glTranslatef [expr {490+($loop1*40.0)}] 40.0 0.0 ; # Move To The Right Of Our Title Text glRotatef [expr {-1.0 * $::player(spin)}] 0.0 0.0 1.0 ; # Rotate Counter Clockwise glColor3f 0.0 1.0 0.0 ; # Set Player Color To Light Green glBegin GL_LINES ; # Start Drawing Our Player Using Lines glVertex2d -5 -5 ; # Top Left Of Player glVertex2d 5 5 ; # Bottom Right Of Player glVertex2d 5 -5 ; # Top Right Of Player glVertex2d -5 5 ; # Bottom Left Of Player glEnd ; # Done Drawing The Player glRotatef [expr {-1.0 * $::player(spin)*0.5}] 0.0 0.0 1.0 ; # Rotate Counter Clockwise glColor3f 0.0 0.75 0.0 ; # Set Player Color To Dark Green glBegin GL_LINES ; # Start Drawing Our Player Using Lines glVertex2d -7 0 ; # Left Center Of Player glVertex2d 7 0 ; # Right Center Of Player glVertex2d 0 -7 ; # Top Center Of Player glVertex2d 0 7 ; # Bottom Center Of Player glEnd ; # Done Drawing The Player } set ::gDemo(filled) 1 ; # Set Filled To True Before Testing glLineWidth 2.0 ; # Set Line Width For Cells To 2.0 glDisable GL_LINE_SMOOTH ; # Disable Antialiasing glLoadIdentity ; # Reset The Current Modelview Matrix for { set loop1 0 } { $loop1 < 11 } { incr loop1 } { for { set loop2 0 } { $loop2 < 11 } { incr loop2 } { set l1 [expr {$loop1*60}] set l2 [expr {$loop2*40}] # Loop From Top To Bottom if { $::hline($loop1,$loop2) } { # Has The Horizontal Line Been Traced glColor3f 1.0 1.0 1.0 ; # If So, Set Line Color To White } else { glColor3f 0.0 0.5 1.0 ; # Set Line Color To Blue } if { $loop1 < 10 } { # Dont Draw To Far Right if { ! $::hline($loop1,$loop2) } { # If A Horizontal Line Isn't Filled set ::gDemo(filled) 0 ; # filled Becomes False } glBegin GL_LINES ; # Start Drawing Horizontal Cell Borders glVertex2d [expr {20+$l1}] [expr {70+$l2}] ; # Left Side Of Horizontal Line glVertex2d [expr {80+$l1}] [expr {70+$l2}] ; # Right Side Of Horizontal Line glEnd ; # Done Drawing Horizontal Cell Borders } if { $::vline($loop1,$loop2) } { # Has The Horizontal Line Been Traced glColor3f 1.0 1.0 1.0 ; # If So, Set Line Color To White } else { glColor3f 0.0 0.5 1.0 ; # Set Line Color To Blue } if { $loop2 < 10 } { # Dont Draw To Far Down if { ! $::vline($loop1,$loop2) } { # If A Verticle Line Isn't Filled set ::gDemo(filled) 0 ; # filled Becomes False } glBegin GL_LINES ; # Start Drawing Verticle Cell Borders glVertex2d [expr {20+$l1}] [expr { 70+$l2}] ; # Left Side Of Horizontal Line glVertex2d [expr {20+$l1}] [expr {110+$l2}] ; # Right Side Of Horizontal Line glEnd ; # Done Drawing Verticle Cell Borders } glEnable GL_TEXTURE_2D ; # Enable Texture Mapping glColor3f 1.0 1.0 1.0 ; # Bright White Color glBindTexture GL_TEXTURE_2D [$::gDemo(texture) get 1] ; # Select The Tile Image if { ($loop1<10) && ($loop2<10) } { # If In Bounds, Fill In Traced Boxes # Are All Sides Of The Box Traced? if { $::hline($loop1,$loop2) && $::hline($loop1,[expr {$loop2+1}]) && \ $::vline($loop1,$loop2) && $::vline([expr {$loop1+1}],$loop2) } { set l1_10 [expr {double($loop1/10.0)}] set l2_10 [expr {double($loop2/10.0)}] glBegin GL_QUADS ; # Draw A Textured Quad glTexCoord2f [expr {$l1_10+0.1}] [expr {1.0-$l2_10}] glVertex2d [expr {20+$l1+59}] [expr {70+$l2+1}] ; # Top Right glTexCoord2f $l1_10 [expr {1.0-$l2_10}] glVertex2d [expr {20+$l1+1}] [expr {70+$l2+1}] ; # Top Left glTexCoord2f $l1_10 [expr {1.0-($l2_10+0.1)}] glVertex2d [expr {20+$l1+1}] [expr {70+$l2+39}] ; # Bottom Left glTexCoord2f [expr {$l1_10+0.1}] [expr {1.0-($l2_10+0.1)}] glVertex2d [expr {20+$l1+59}] [expr {70+$l2+39}] ; # Bottom Right glEnd ; # Done Texturing The Box } } glDisable GL_TEXTURE_2D ; # Disable Texture Mapping } } glLineWidth 1.0 ; # Set The Line Width To 1.0 if { $::gDemo(anti) } { # Is Anti TRUE? glEnable GL_LINE_SMOOTH ; # If So, Enable Antialiasing } if { $::hourglass(fx) == 1 } { # If fx=1 Draw The Hourglass glLoadIdentity ; # Reset The Modelview Matrix # Move To The Fine Hourglass Position glTranslatef [expr {20.0+($::hourglass(x)*60)}] [expr {70.0+($::hourglass(y)*40)}] 0.0 glRotatef $::hourglass(spin) 0.0 0.0 1.0 ; # Rotate Clockwise glColor3ub [expr [IntRand]%255] [expr [IntRand]%255] [expr [IntRand]%255] glBegin GL_LINES ; # Start Drawing Our Hourglass Using Lines glVertex2d -5 -5 ; # Top Left Of Hourglass glVertex2d 5 5 ; # Bottom Right Of Hourglass glVertex2d 5 -5 ; # Top Right Of Hourglass glVertex2d -5 5 ; # Bottom Left Of Hourglass glVertex2d -5 5 ; # Bottom Left Of Hourglass glVertex2d 5 5 ; # Bottom Right Of Hourglass glVertex2d -5 -5 ; # Top Left Of Hourglass glVertex2d 5 -5 ; # Top Right Of Hourglass glEnd ; # Done Drawing The Hourglass } glLoadIdentity ; # Reset The Modelview Matrix # Move To The Fine Player Position glTranslatef [expr {$::player(fx)+20.0}] [expr {$::player(fy)+70.0}] 0.0 glRotatef $::player(spin) 0.0 0.0 1.0 ; # Rotate Clockwise glColor3f 0.0 1.0 0.0 ; # Set Player Color To Light Green glBegin GL_LINES ; # Start Drawing Our Player Using Lines glVertex2d -5 -5 ; # Top Left Of Player glVertex2d 5 5 ; # Bottom Right Of Player glVertex2d 5 -5 ; # Top Right Of Player glVertex2d -5 5 ; # Bottom Left Of Player glEnd ; # Done Drawing The Player glRotatef [expr {$::player(spin)*0.5}] 0.0 0.0 1.0 ; # Rotate Clockwise glColor3f 0.0 0.75 0.0 ; # Set Player Color To Dark Green glBegin GL_LINES ; # Start Drawing Our Player Using Lines glVertex2d -7 0 ; # Left Center Of Player glVertex2d 7 0 ; # Right Center Of Player glVertex2d 0 -7 ; # Top Center Of Player glVertex2d 0 7 ; # Bottom Center Of Player glEnd ; # Done Drawing The Player set num [expr {$::gDemo(stage) * $::gDemo(level)}] for { set loop1 0 } { $loop1 < $num } { incr loop1 } { glLoadIdentity ; # Reset The Modelview Matrix glTranslatef [expr {$::enemy($loop1,fx)+20.0}] [expr {$::enemy($loop1,fy)+70.0}] 0.0 glColor3f 1.0 0.5 0.5 ; # Make Enemy Body Pink glBegin GL_LINES ; # Start Drawing Enemy glVertex2d 0 -7 ; # Top Point Of Body glVertex2d -7 0 ; # Left Point Of Body glVertex2d -7 0 ; # Left Point Of Body glVertex2d 0 7 ; # Bottom Point Of Body glVertex2d 0 7 ; # Bottom Point Of Body glVertex2d 7 0 ; # Right Point Of Body glVertex2d 7 0 ; # Right Point Of Body glVertex2d 0 -7 ; # Top Point Of Body glEnd ; # Done Drawing Enemy Body glRotatef $::enemy($loop1,spin) 0.0 0.0 1.0 ; # Rotate The Enemy Blade glColor3f 1.0 0.0 0.0 ; # Make Enemy Blade Red glBegin GL_LINES ; # Start Drawing Enemy Blade glVertex2d -7 -7 ; # Top Left Of Enemy glVertex2d 7 7 ; # Bottom Right Of Enemy glVertex2d -7 7 ; # Bottom Left Of Enemy glVertex2d 7 -7 ; # Top Right Of Enemy glEnd ; # Done Drawing Enemy Blade } $toglwin swapbuffers HandleLogic } proc Cleanup {} { unset ::vline unset ::hline unset ::enemy unset ::hourglass unset ::player unset ::keys } # Put all exit related code here. proc ExitProg {} { KillFont exit } proc ToggleAnti {} { set ::gDemo(anti) [expr 1 - $::gDemo(anti)] } proc SetKeys { type onOff } { set ::keys($type) $onOff } 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 } } # Create the OpenGL window and some Tk helper widgets. proc CreateWindow {} { frame .fr pack .fr -expand 1 -fill both # Create Our OpenGL Window togl .fr.toglwin -width $::gDemo(winWidth) -height $::gDemo(winHeight) \ -swapinterval 1 \ -double true -depth true \ -createproc CreateCallback \ -reshapeproc ReshapeCallback \ -displayproc DisplayCallback grid .fr.toglwin -row 0 -column 0 -sticky news grid rowconfigure .fr 0 -weight 1 grid columnconfigure .fr 0 -weight 1 wm title . "Tcl3D demo: NeHe's Line Tutorial (Lesson 21)" # Watch For ESC Key And Quit Messages wm protocol . WM_DELETE_WINDOW "ExitProg" bind .