OUTPUT BUFFER:
# Lesson22.tcl # # NeHe's GL_ARB_multitexture & Bump Mapping Tutorial # # This Code Was Created by Jens Schneider (WizardSoft) 2000 # Lesson22 to the series of OpenGL tutorials by NeHe-Production # # This Code is loosely based upon Lesson06 by Jeff Molofee. # contact me at: schneide@pool.informatik.rwth-aachen.de # # Basecode 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/08/16 # See www.tcl3d.org for the Tcl3D extension. package require Img package require tcl3d 0.5.0 set MAX_EMBOSS 0.008 ; # Maximum Emboss-Translate. Increase To Get Higher Immersion # At A Cost Of Lower Quality (More Artifacts Will Occur!) # Here Comes The ARB-Multitexture Support. # There Are (Optimally) 6 New Commands To The OpenGL Set: # glMultiTexCoordifARB i=1..4 : Sets Texture-Coordinates For Texel-Pipeline #i # glActiveTextureARB : Sets Active Texel-Pipeline # glClientActiveTextureARB : Sets Active Texel-Pipeline For The Pointer-Array-Commands # # There Are Even More For The Various Formats Of glMultiTexCoordi{f,fv,d,i}, # But We Don't Need Them. # Font to be used in the Tk listbox. set listFont {-family {Courier} -size 10} # Determine the directory of this script. set gDemo(scriptDir) [file dirname [info script]] # Display mode. set fullScreen false # Window size. set gDemo(winWidth) 640 set gDemo(winHeight) 480 set xrot 0.0 ; # X Rotation set yrot 0.0 ; # Y Rotation set xspeed 0.1 ; # X Rotation Speed set yspeed 0.0 ; # Y Rotation Speed set z -5.0 ; # Depth Into The Screen set LightAmbient { 0.2 0.2 0.2 } ; # Ambient Light is 20% white set LightDiffuse { 1.0 1.0 1.0 } ; # Diffuse Light is white set LightPosition { 0.0 0.0 2.0 } ; # Position is somewhat in front of screen set __ARB_ENABLE 1 ; # Used To Disable ARB Extensions Entirely set multitextureSupported 0 ; # Flag Indicating Whether Multitexturing Is Supported set useMultitexture 1 ; # Use It If It Is Supported? set maxTexelUnits 1 ; # Number Of Texel-Pipelines. This Is At Least 1. set emboss 0 ; # Emboss Only, No Basetexture? set bumps 1 ; # Do Bumpmapping? set filter 1 ; # Which Filter To Use set texture [tcl3dVector GLuint 3] ; # Storage For 3 Textures set bump [tcl3dVector GLuint 3] ; # Our Bumpmappings set invbump [tcl3dVector GLuint 3] ; # Inverted Bumpmaps set glLogo [tcl3dVector GLuint 1] ; # Handle For OpenGL-Logo set multiLogo [tcl3dVector GLuint 1] ; # Handle For Multitexture-Enabled-Logo set Gray { 0.5 0.5 0.5 1.0 } # Data Contains The Faces For The Cube In Format 2xTexCoord, 3xVertex; # Note That The Tesselation Of The Cube Is Only Absolute Minimum. # Face ordering: Front, Back, Top, Bottom, Right, Left. set data [list \ 0.0 0.0 -1.0 -1.0 1.0 \ 1.0 0.0 1.0 -1.0 1.0 \ 1.0 1.0 1.0 1.0 1.0 \ 0.0 1.0 -1.0 1.0 1.0 \ 1.0 0.0 -1.0 -1.0 -1.0 \ 1.0 1.0 -1.0 1.0 -1.0 \ 0.0 1.0 1.0 1.0 -1.0 \ 0.0 0.0 1.0 -1.0 -1.0 \ 0.0 1.0 -1.0 1.0 -1.0 \ 0.0 0.0 -1.0 1.0 1.0 \ 1.0 0.0 1.0 1.0 1.0 \ 1.0 1.0 1.0 1.0 -1.0 \ 1.0 1.0 -1.0 -1.0 -1.0 \ 0.0 1.0 1.0 -1.0 -1.0 \ 0.0 0.0 1.0 -1.0 1.0 \ 1.0 0.0 -1.0 -1.0 1.0 \ 1.0 0.0 1.0 -1.0 -1.0 \ 1.0 1.0 1.0 1.0 -1.0 \ 0.0 1.0 1.0 1.0 1.0 \ 0.0 0.0 1.0 -1.0 1.0 \ 0.0 0.0 -1.0 -1.0 -1.0 \ 1.0 0.0 -1.0 -1.0 1.0 \ 1.0 1.0 -1.0 1.0 1.0 \ 0.0 1.0 -1.0 1.0 -1.0 \ ] # Show errors occuring in the Togl callbacks. proc bgerror { msg } { 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 } } 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 {} { if { $::fullScreen } { SetFullScreenMode . set ::fullScreen false } else { SetWindowMode . $::gDemo(winWidth) $::gDemo(winHeight) set ::fullScreen true } } proc ToggleEmboss {} { set ::emboss [expr 1 - $::emboss] .fr.toglwin postredisplay } proc ToggleMultitexture {} { set ::useMultitexture [expr (1 - $::useMultitexture) && $::multitextureSupported] .fr.toglwin postredisplay } proc ToggleBumps {} { set ::bumps [expr 1 - $::bumps] .fr.toglwin postredisplay } proc ToggleFilter {} { incr ::filter if { $::filter > 2 } { set ::filter 0 } .fr.toglwin postredisplay } proc SetXSpeed { val } { set ::xspeed [expr $::xspeed + $val] } proc SetYSpeed { val } { set ::yspeed [expr $::yspeed + $val] } proc SetDepth { val } { set ::z [expr $::z + $val] } # initMultitexture Checks At Run-Time If Multitexturing Is Supported proc initMultitexture {} { if { [tcl3dOglHaveExtension "GL_ARB_multitexture"] && \ $::__ARB_ENABLE && \ [tcl3dOglHaveExtension "GL_EXT_texture_env_combine"] } { set ::maxTexelUnits [tcl3dOglGetMaxTextureUnits] puts "GL_ARB_multitexture extension found ($::maxTexelUnits texel units)" return 1 } puts "GL_ARB_multitexture extension not found" set ::useMultitexture 0 ; # We Can't Use It If It Isn't Supported! return 0 } proc initLights {} { glLightfv GL_LIGHT1 GL_AMBIENT $::LightAmbient ; # Load Light-Parameters Into GL_LIGHT1 glLightfv GL_LIGHT1 GL_DIFFUSE $::LightDiffuse glLightfv GL_LIGHT1 GL_POSITION $::LightPosition glEnable GL_LIGHT1 } proc LoadImage { imgName numChans } { if { $numChans != 3 && $numChans != 4 } { error "Error: Only 3 or 4 channels allowed ($numChans supplied)" } 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 texImg [tcl3dVectorFromPhoto $phImg $numChans] image delete $phImg } return [list $texImg $w $h] } # Load Bitmaps And Convert To Textures proc LoadGLTextures {} { # Load The Tile-Bitmap For Base-Texture set imgInfo [LoadImage "Base.bmp" 3] set imgData [lindex $imgInfo 0] set imgWidth [lindex $imgInfo 1] set imgHeight [lindex $imgInfo 2] glGenTextures 3 $::texture ; # Create Three Textures # Create Nearest Filtered Texture glBindTexture GL_TEXTURE_2D [$::texture get 0] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_NEAREST glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_NEAREST glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create Linear Filtered Texture glBindTexture GL_TEXTURE_2D [$::texture get 1] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create MipMapped Texture glBindTexture GL_TEXTURE_2D [$::texture get 2] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR_MIPMAP_NEAREST gluBuild2DMipmaps GL_TEXTURE_2D $::GL_RGB8 $imgWidth $imgHeight GL_RGB GL_UNSIGNED_BYTE $imgData # Delete the image data vector. $imgData delete # Load The Bumpmaps set imgInfo [LoadImage "Bump.bmp" 3] set imgData [lindex $imgInfo 0] set imgWidth [lindex $imgInfo 1] set imgHeight [lindex $imgInfo 2] glPixelTransferf GL_RED_SCALE 0.5 ; # Scale RGB By 50%, So That We Have Only glPixelTransferf GL_GREEN_SCALE 0.5 ; # Half Intenstity glPixelTransferf GL_BLUE_SCALE 0.5 glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $::GL_CLAMP ; # No Wrapping, Please! glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $::GL_CLAMP glTexParameterfv GL_TEXTURE_2D GL_TEXTURE_BORDER_COLOR $::Gray glGenTextures 3 $::bump ; # Create Three Textures # Create Nearest Filtered Texture glBindTexture GL_TEXTURE_2D [$::bump get 0] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_NEAREST glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_NEAREST glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create Linear Filtered Texture glBindTexture GL_TEXTURE_2D [$::bump get 1] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create MipMapped Texture glBindTexture GL_TEXTURE_2D [$::bump get 2] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR_MIPMAP_NEAREST gluBuild2DMipmaps GL_TEXTURE_2D $::GL_RGB8 $imgWidth $imgHeight GL_RGB GL_UNSIGNED_BYTE $imgData tcl3dVectorManip $imgData $imgWidth $imgHeight 3 -1 255 ; # Invert The Bumpmap glGenTextures 3 $::invbump ; # Create Three Textures # Create Nearest Filtered Texture glBindTexture GL_TEXTURE_2D [$::invbump get 0] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_NEAREST glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_NEAREST glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create Linear Filtered Texture glBindTexture GL_TEXTURE_2D [$::invbump get 1] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexImage2D GL_TEXTURE_2D 0 $::GL_RGB8 $imgWidth $imgHeight 0 GL_RGB GL_UNSIGNED_BYTE $imgData # Create MipMapped Texture glBindTexture GL_TEXTURE_2D [$::invbump get 2] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR_MIPMAP_NEAREST gluBuild2DMipmaps GL_TEXTURE_2D $::GL_RGB8 $imgWidth $imgHeight GL_RGB GL_UNSIGNED_BYTE $imgData glPixelTransferf GL_RED_SCALE 1.0 ; # Scale RGB Back To 100% Again glPixelTransferf GL_GREEN_SCALE 1.0 glPixelTransferf GL_BLUE_SCALE 1.0 # Delete the image data vector. $imgData delete # Load The Logo-Bitmaps set imgInfo [LoadImage "OpenGL_Alpha.bmp" 3] set imgData [lindex $imgInfo 0] set imgWidth [lindex $imgInfo 1] set imgHeight [lindex $imgInfo 2] set alphaImg [tcl3dVector GLubyte [expr $imgWidth * $imgHeight * 4]] ; # Create Memory For RGBA8-Texture tcl3dVectorCopyChannel $imgData $alphaImg 0 3 $imgWidth $imgHeight 3 4 ; # Pick Only Red Value As Alpha $imgData delete set imgInfo [LoadImage "OpenGL.bmp" 3] set imgData [lindex $imgInfo 0] tcl3dVectorCopyChannel $imgData $alphaImg 0 0 $imgWidth $imgHeight 3 4 ; # Red tcl3dVectorCopyChannel $imgData $alphaImg 1 1 $imgWidth $imgHeight 3 4 ; # Green tcl3dVectorCopyChannel $imgData $alphaImg 2 2 $imgWidth $imgHeight 3 4 ; # Blue $imgData delete glGenTextures 1 $::glLogo ; # Create One Texture # Create Linear Filtered RGBA8-Texture glBindTexture GL_TEXTURE_2D [$::glLogo get 0] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexImage2D GL_TEXTURE_2D 0 $::GL_RGBA8 $imgWidth $imgHeight 0 GL_RGBA GL_UNSIGNED_BYTE $alphaImg $alphaImg delete # Load The "Extension Enabled"-Logo set imgInfo [LoadImage "Multi_On_Alpha.bmp" 3] set imgData [lindex $imgInfo 0] set imgWidth [lindex $imgInfo 1] set imgHeight [lindex $imgInfo 2] set alphaImg [tcl3dVector GLubyte [expr $imgWidth * $imgHeight * 4]] tcl3dVectorCopyChannel $imgData $alphaImg 0 3 $imgWidth $imgHeight 3 4 ; # Pick Only Red Value As Alpha $imgData delete set imgInfo [LoadImage "Multi_On.bmp" 3] set imgData [lindex $imgInfo 0] tcl3dVectorCopyChannel $imgData $alphaImg 0 0 $imgWidth $imgHeight 3 4 ; # Red tcl3dVectorCopyChannel $imgData $alphaImg 1 1 $imgWidth $imgHeight 3 4 ; # Green tcl3dVectorCopyChannel $imgData $alphaImg 2 2 $imgWidth $imgHeight 3 4 ; # Blue $imgData delete glGenTextures 1 $::multiLogo ; # Create One Texture # Create Linear Filtered RGBA8-Texture glBindTexture GL_TEXTURE_2D [$::multiLogo get 0] glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR glTexImage2D GL_TEXTURE_2D 0 $::GL_RGBA8 $imgWidth $imgHeight 0 GL_RGBA GL_UNSIGNED_BYTE $alphaImg $alphaImg delete } # 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 # Calculate The Aspect Ratio Of The Window gluPerspective 45.0 [expr double($w)/double($h)] 0.1 100.0 glMatrixMode GL_MODELVIEW ; # Select The Modelview Matrix glLoadIdentity ; # Reset The Modelview Matrix set ::gDemo(winWidth) $w set ::gDemo(winHeight) $h } proc doCube {} { global data glBegin GL_QUADS # Front Face glNormal3f 0.0 0.0 1.0 for { set i 0 } { $i < 4 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } # Back Face glNormal3f 0.0 0.0 -1.0 for { set i 4 } { $i < 8 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } # Top Face glNormal3f 0.0 1.0 0.0 for { set i 8 } { $i < 12 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } # Bottom Face glNormal3f 0.0 -1.0 0.0 for { set i 12 } { $i < 16 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } # Right face glNormal3f 1.0 0.0 0.0 for { set i 16 } { $i < 20 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } # Left Face glNormal3f -1.0 0.0 0.0 for { set i 20 } { $i < 24 } { incr i } { set ind [expr 5 * $i] glTexCoord2f [lindex $data $ind] [lindex $data [expr $ind+1]] glVertex3f [lindex $data [expr $ind+2]] [lindex $data [expr $ind+3]] [lindex $data [expr $ind+4]] } glEnd } # All Setup For OpenGL Goes Here proc CreateCallback { toglwin } { set ::multitextureSupported [initMultitexture] LoadGLTextures ; # Jump To Texture Loading Routine glEnable GL_TEXTURE_2D ; # Enable Texture Mapping glShadeModel GL_SMOOTH ; # Enable Smooth Shading glClearColor 0.0 0.0 0.0 0.5 ; # Black Background glClearDepth 1.0 ; # Depth Buffer Setup glEnable GL_DEPTH_TEST ; # Enables Depth Testing glDepthFunc GL_LEQUAL ; # The Type Of Depth Testing To Do glHint GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST ; # Really Nice Perspective Calculations initLights ; # Initialize OpenGL Light } # Okay, Here Comes The Important Stuff: # # On http://www.nvidia.com/marketing/Developer/DevRel.nsf/TechnicalDemosFrame?OpenPage # You Can Find A Demo Called GL_BUMP That Is A Little Bit More Complicated. # GL_BUMP: Copyright Diego Tártara, 1999. # - diego_tartara@ciudad.com.ar - # # The Idea Behind GL_BUMP Is, That You Compute The Texture-Coordinate Offset As Follows: # 0) All Coordinates Either In Object Or In World Space. # 1) Calculate Vertex v From Actual Position (The Vertex You're At) To The Lightposition # 2) Normalize v # 3) Project This v Into Tangent Space. # Tangent Space Is The Plane "Touching" The Object In Our Current Position On It. # Typically, If You're Working With Flat Surfaces, This Is The Surface Itself. # 4) Offset s,t-Texture-Coordinates By The Projected v's x And y-Component. # # * This Would Be Called Once Per Vertex In Our Geometry, If Done Correctly. # * This Might Lead To Incoherencies In Our Texture Coordinates, But Is Ok As Long As You Did Not # * Wrap The Bumpmap. # # Basically, We Do It The Same Way With Some Exceptions: # ad 0) We'll Work In Object Space All Time. This Has The Advantage That We'll Only # Have To Transform The Lightposition From Frame To Frame. This Position Obviously # Has To Be Transformed Using The Inversion Of The Modelview Matrix. This Is, However, # A Considerable Drawback, If You Don't Know How Your Modelview Matrix Was Built, Since # Inverting A Matrix Is Costly And Complicated. # ad 1) Do It Exactly That Way. # ad 2) Do It Exactly That Way. # ad 3) To Project The Lightvector Into Tangent Space, We'll Support The Setup-Routine # With Two Directions: One Of Increasing s-Texture-Coordinate Axis, The Other In # Increasing t-Texture-Coordinate Axis. The Projection Simply Is (Assumed Both # texCoord Vectors And The Lightvector Are Normalized) The Dotproduct Between The # Respective texCoord Vector And The Lightvector. # ad 4) The Offset Is Computed By Taking The Result Of Step 3 And Multiplying The Two # Numbers With MAX_EMBOSS, A Constant That Specifies How Much Quality We're Willing To # Trade For Stronger Bump-Effects. Just Temper A Little Bit With MAX_EMBOSS! # # WHY THIS IS COOL: # * Have A Look! # * Very Cheap To Implement (About One Squareroot And A Couple Of MULs)! # * Can Even Be Further Optimized! # * SetUpBump Doesn't Disturb glBegin()/glEnd() # * THIS DOES ALWAYS WORK - Not Only With XY-Tangent Spaces!! # # DRAWBACKS: # * Must Know "Structure" Of Modelview-Matrix Or Invert It. Possible To Do The Whole Thing # * In World Space, But This Involves One Transformation For Each Vertex! # proc SetUpBumps { n c l s t } { set v [tcl3dVector GLfloat 3] ; # Vertex From Current Position To Light set cv [tcl3dVectorFromList GLfloat $c] # Calculate v From Current Vector c To Lightposition And Normalize v tcl3dVec3fSubtract $l $cv $v tcl3dVec3fNormalize $v # Project v Such That We Get Two Values Along Each Texture-Coordinat Axis. set retList $c lset retList 0 [expr ([lindex $s 0]*[$v get 0] + [lindex $s 1]*[$v get 1] + [lindex $s 2]*[$v get 2])*$::MAX_EMBOSS] lset retList 1 [expr ([lindex $t 0]*[$v get 0] + [lindex $t 1]*[$v get 1] + [lindex $t 2]*[$v get 2])*$::MAX_EMBOSS] return $retList } # MUST CALL THIS LAST!!!, Billboards The Two Logos. proc doLogo {} { glDepthFunc GL_ALWAYS glBlendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA glEnable GL_BLEND glDisable GL_LIGHTING glLoadIdentity glBindTexture GL_TEXTURE_2D [$::glLogo get 0] glBegin GL_QUADS glTexCoord2f 0.0 0.0 ; glVertex3f 0.23 -0.4 -1.0 glTexCoord2f 1.0 0.0 ; glVertex3f 0.53 -0.4 -1.0 glTexCoord2f 1.0 1.0 ; glVertex3f 0.53 -0.25 -1.0 glTexCoord2f 0.0 1.0 ; glVertex3f 0.23 -0.25 -1.0 glEnd if { $::useMultitexture } { glBindTexture GL_TEXTURE_2D [$::multiLogo get 0] glBegin GL_QUADS glTexCoord2f 0.0 0.0 ; glVertex3f -0.53 -0.4 -1.0 glTexCoord2f 1.0 0.0 ; glVertex3f -0.33 -0.4 -1.0 glTexCoord2f 1.0 1.0 ; glVertex3f -0.33 -0.3 -1.0 glTexCoord2f 0.0 1.0 ; glVertex3f -0.53 -0.3 -1.0 glEnd } glDepthFunc GL_LEQUAL } proc doMesh1TexelUnits {} { global data #puts "doMesh1" set c {0.0 0.0 0.0} ; # Holds Current Vertex set n {0.0 0.0 0.0} ; # Normalized Normal Of Current Surface set s {0.0 0.0 0.0} ; # s-Texture Coordinate Direction, Normalized set t {0.0 0.0 0.0} ; # t-Texture Coordinate Direction, Normalized set M [tcl3dVector GLfloat 16] ; # Holds The Modelview Matrix. set Minv [tcl3dVector GLfloat 16] ; # Holds The Inverted Modelview Matrix To Do So. # Clear Screen And Depth Buffer glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT] # Build Inverse Modelview Matrix First. This Substitutes One Push/Pop With One glLoadIdentity(); # Simply Build It By Doing All Transformations Negated And In Reverse Order. glLoadIdentity glRotatef [expr {-1.0 * $::yrot}] 0.0 1.0 0.0 glRotatef [expr {-1.0 * $::xrot}] 1.0 0.0 0.0 glTranslatef 0.0 0.0 [expr {-1.0 * $::z}] glGetFloatv GL_MODELVIEW_MATRIX $M glLoadIdentity glTranslatef 0.0 0.0 $::z glRotatef $::xrot 1.0 0.0 0.0 glRotatef $::yrot 0.0 1.0 0.0 # Transform The Lightposition Into Object Coordinates: set l [tcl3dVectorFromList GLfloat $::LightPosition] tcl3dMatfTranspose $M $Minv tcl3dMatfTransformPoint $l $Minv $l # PASS#1: Use Texture "Bump" # No Blend # No Lighting # No Offset Texture-Coordinates glBindTexture GL_TEXTURE_2D [$::bump get $::filter] glDisable GL_BLEND glDisable GL_LIGHTING doCube # PASS#2: Use Texture "Invbump" # Blend GL_ONE To GL_ONE # No Lighting # Offset Texture Coordinates glBindTexture GL_TEXTURE_2D [$::invbump get $::filter] glBlendFunc GL_ONE GL_ONE glDepthFunc GL_LEQUAL glEnable GL_BLEND glBegin GL_QUADS # Front Face set n { 0.0 0.0 1.0 } set s { 1.0 0.0 0.0 } set t { 0.0 1.0 0.0 } for { set i 0 } { $i < 4 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Back Face set n { 0.0 0.0 -1.0 } set s { -1.0 0.0 0.0 } set t { 0.0 1.0 0.0 } for { set i 4 } { $i < 8 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Top Face set n { 0.0 1.0 0.0 } set s { 1.0 0.0 0.0 } set t { 0.0 0.0 -1.0 } for { set i 8 } { $i < 12 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Bottom Face set n { 0.0 -1.0 0.0 } set s { -1.0 0.0 0.0 } set t { 0.0 0.0 -1.0 } for { set i 12 } { $i < 16 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Right Face set n { 1.0 0.0 0.0 } set s { 0.0 0.0 -1.0 } set t { 0.0 1.0 0.0 } for { set i 16 } { $i < 20 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Left Face set n { -1.0 0.0 0.0 } set s { 0.0 0.0 1.0 } set t { 0.0 1.0 0.0 } for { set i 20 } { $i < 24 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glTexCoord2f [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } glEnd # PASS#3: Use Texture "Base" # Blend GL_DST_COLOR To GL_SRC_COLOR (Multiplies By 2) # Lighting Enabled # No Offset Texture-Coordinates if { ! $::emboss } { glTexEnvf GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE $::GL_MODULATE glBindTexture GL_TEXTURE_2D [$::texture get $::filter] glBlendFunc GL_DST_COLOR GL_SRC_COLOR glEnable GL_LIGHTING doCube } set ::xrot [expr {$::xrot + $::xspeed}] set ::yrot [expr {$::yrot + $::yspeed}] if { $::xrot > 360.0 } { set ::xrot [expr {$::xrot - 360.0}] } if { $::xrot < 0.0 } { set ::xrot [expr {$::xrot + 360.0}] } if { $::yrot > 360.0 } { set ::yrot [expr {$::yrot - 360.0}] } if { $::yrot < 0.0 } { set ::yrot [expr {$::yrot + 360.0}] } # LAST PASS: Do The Logos doLogo } proc doMesh2TexelUnits {} { global data #puts "doMesh2" set c {0.0 0.0 0.0} ; # Holds Current Vertex set n {0.0 0.0 0.0} ; # Normalized Normal Of Current Surface set s {0.0 0.0 0.0} ; # s-Texture Coordinate Direction, Normalized set t {0.0 0.0 0.0} ; # t-Texture Coordinate Direction, Normalized set M [tcl3dVector GLfloat 16] ; # Holds The Modelview Matrix. set Minv [tcl3dVector GLfloat 16] ; # Holds The Inverted Modelview Matrix To Do So. # Clear Screen And Depth Buffer glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT] # Build Inverse Modelview Matrix First. This Substitutes One Push/Pop With One glLoadIdentity(); # Simply Build It By Doing All Transformations Negated And In Reverse Order. glLoadIdentity glRotatef [expr {-1.0 * $::yrot}] 0.0 1.0 0.0 glRotatef [expr {-1.0 * $::xrot}] 1.0 0.0 0.0 glTranslatef 0.0 0.0 [expr {-1.0 * $::z}] glGetFloatv GL_MODELVIEW_MATRIX $M glLoadIdentity glTranslatef 0.0 0.0 $::z glRotatef $::xrot 1.0 0.0 0.0 glRotatef $::yrot 0.0 1.0 0.0 # Transform The Lightposition Into Object Coordinates: set l [tcl3dVectorFromList GLfloat $::LightPosition] tcl3dMatfTranspose $M $Minv tcl3dMatfTransformPoint $l $Minv $l # PASS#1: Texel-Unit 0: Use Texture "Bump" # No Blend # No Lighting # No Offset Texture-Coordinates # Texture-Operation "Replace" # Texel-Unit 1: Use Texture "Invbump" # No Lighting # Offset Texture Coordinates # Texture-Operation "Replace" # TEXTURE-UNIT #0 glActiveTextureARB GL_TEXTURE0_ARB glEnable GL_TEXTURE_2D glBindTexture GL_TEXTURE_2D [$::bump get $::filter] glTexEnvf GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE $::GL_COMBINE_EXT glTexEnvf GL_TEXTURE_ENV GL_COMBINE_RGB_EXT $::GL_REPLACE # TEXTURE-UNIT #1: glActiveTextureARB GL_TEXTURE1_ARB glEnable GL_TEXTURE_2D glBindTexture GL_TEXTURE_2D [$::invbump get $::filter] glTexEnvf GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE $::GL_COMBINE_EXT glTexEnvf GL_TEXTURE_ENV GL_COMBINE_RGB_EXT $::GL_ADD # General Switches: glDisable GL_BLEND glDisable GL_LIGHTING glBegin GL_QUADS # Front Face set n { 0.0 0.0 1.0 } set s { 1.0 0.0 0.0 } set t { 0.0 1.0 0.0 } for { set i 0 } { $i < 4 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Back Face set n { 0.0 0.0 -1.0 } set s { -1.0 0.0 0.0 } set t { 0.0 1.0 0.0 } for { set i 4 } { $i < 8 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Top Face set n { 0.0 1.0 0.0 } set s { 1.0 0.0 0.0 } set t { 0.0 0.0 -1.0 } for { set i 8 } { $i < 12 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Bottom Face set n { 0.0 -1.0 0.0 } set s { -1.0 0.0 0.0 } set t { 0.0 0.0 -1.0 } for { set i 12 } { $i < 16 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Right Face set n { 1.0 0.0 0.0 } set s { 0.0 0.0 -1.0 } set t { 0.0 1.0 0.0 } for { set i 16 } { $i < 20 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } # Left Face set n { -1.0 0.0 0.0 } set s { 0.0 0.0 1.0 } set t { 0.0 1.0 0.0 } for { set i 20 } { $i < 24 } { incr i } { set ind [expr 5 * $i] lset c 0 [lindex $data [expr {$ind + 2}]] lset c 1 [lindex $data [expr {$ind + 3}]] lset c 2 [lindex $data [expr {$ind + 4}]] set c [SetUpBumps $n $c $l $s $t] glMultiTexCoord2fARB GL_TEXTURE0_ARB \ [lindex $data $ind] [lindex $data [expr {$ind+1}]] glMultiTexCoord2fARB GL_TEXTURE1_ARB \ [expr {[lindex $data $ind] + [lindex $c 0]}] \ [expr {[lindex $data [expr {$ind+1}]] + [lindex $c 1]}] glVertex3f [lindex $data [expr {$ind+2}]] \ [lindex $data [expr {$ind+3}]] \ [lindex $data [expr {$ind+4}]] } glEnd # PASS#2 Use Texture "Base" # Blend GL_DST_COLOR To GL_SRC_COLOR (Multiplies By 2) # Lighting Enabled # No Offset Texture-Coordinates glActiveTextureARB GL_TEXTURE1_ARB glDisable GL_TEXTURE_2D glActiveTextureARB GL_TEXTURE0_ARB if { ! $::emboss } { glTexEnvf GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE $::GL_MODULATE glBindTexture GL_TEXTURE_2D [$::texture get $::filter] glBlendFunc GL_DST_COLOR GL_SRC_COLOR glEnable GL_BLEND glEnable GL_LIGHTING doCube } set ::xrot [expr {$::xrot + $::xspeed}] set ::yrot [expr {$::yrot + $::yspeed}] if { $::xrot > 360.0 } { set ::xrot [expr {$::xrot - 360.0}] } if { $::xrot < 0.0 } { set ::xrot [expr {$::xrot + 360.0}] } if { $::yrot > 360.0 } { set ::yrot [expr {$::yrot - 360.0}] } if { $::yrot < 0.0 } { set ::yrot [expr {$::yrot + 360.0}] } # LAST PASS: Do The Logos doLogo } proc doMeshNoBumps {} { #puts "doMeshNoBumps" # Clear Screen And Depth Buffer glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT] glLoadIdentity ; # Reset The Current Modelview Matrix glTranslatef 0.0 0.0 $::z glRotatef $::xrot 1.0 0.0 0.0 glRotatef $::yrot 0.0 1.0 0.0 if { $::useMultitexture } { glActiveTextureARB GL_TEXTURE1_ARB glDisable GL_TEXTURE_2D glActiveTextureARB GL_TEXTURE0_ARB } glDisable GL_BLEND glBindTexture GL_TEXTURE_2D [$::texture get $::filter] glBlendFunc GL_DST_COLOR GL_SRC_COLOR glEnable GL_LIGHTING doCube set ::xrot [expr {$::xrot + $::xspeed}] set ::yrot [expr {$::yrot + $::yspeed}] if { $::xrot > 360.0 } { set ::xrot [expr {$::xrot - 360.0}] } if { $::xrot < 0.0 } { set ::xrot [expr {$::xrot + 360.0}] } if { $::yrot > 360.0 } { set ::yrot [expr {$::yrot - 360.0}] } if { $::yrot < 0.0 } { set ::yrot [expr {$::yrot + 360.0}] } # LAST PASS: Do The Logos doLogo } 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 } } # Here's Where We Do All The Drawing proc DisplayCallback { toglwin } { # 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] if { $::bumps } { if { $::useMultitexture && ($::maxTexelUnits > 1) } { doMesh2TexelUnits } else { doMesh1TexelUnits } } else { doMeshNoBumps } $toglwin swapbuffers } # Put all exit related code here. proc ExitProg {} { exit } # 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) \ -double true -depth true -alpha true \ -createproc CreateCallback \ -reshapeproc ReshapeCallback \ -displayproc DisplayCallback listbox .fr.usage -font $::listFont -height 10 label .fr.info grid .fr.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: NeHe's GL_ARB_multitexture & Bump Mapping Tutorial (Lesson 22)" # Watch For ESC Key And Quit Messages wm protocol . WM_DELETE_WINDOW "ExitProg" bind .