#
# OpenGL 4.0 with GLEW - Example 13
#
# Method for Real-Time LOD Terrain Rendering on Modern GPU
#
# @author Norbert Nopper norbert@nopper.tv
# @version 05.03.2010
#
# Homepage: https://github.com/McNopper/OpenGL
#
# Copyright Norbert Nopper
#
# Modified for Tcl3D by Paul Obermeier 2011/02/03
# See www.tcl3d.org for the Tcl3D extension.
package require Tk
package require Img
package require tcl3d
# Font to be used in the Tk listbox.
set g_Demo(listFont) {-family {Courier} -size 10}
# Obtain the name of this script file.
set g_Demo(scriptDir) [file dirname [info script]]
# Window size.
set g_Demo(winWidth) 640
set g_Demo(winHeight) 480
# The space when travelling horizontal form one pixel to the next in meters.
set g_Demo(horizontalPixelSpacing) 60.0
# One turn takes x seconds.
set g_Demo(turnDuration) 20.0
# The space when travelling all pixel colors in meters.
set g_Demo(verticalPixelRange) 10004.0
# The scale to convert the real world meters in virtual worls scale.
set g_Demo(metersToVirtualWorldScale) 5.0
# The circle around radius.
set g_Demo(radius) 6000.0
# The normal map of the terrain. Width and height does not have to be the same,
# but they have to be power of two plus one.
set g_Demo(normalMap) "grand_canyon_normal.jpg"
# The height map of the terrain. Width and height does not have to be the same,
# but they have to be power of two plus one.
set g_Demo(heightMap) "grand_canyon_height.jpg"
# The color map of the terrain.
set g_Demo(colorMap) "grand_canyon_color.jpg"
# Flags for switching between viewing modes.
set g_Demo(filled) true
set g_Demo(animationOn) true
set g_Demo(topViewActive) true
# The maximum detail level which is 2^s = sMapExtend
set g_Demo(sMaxDetailLevel) 0
# The maximum detail level which is 2^t = tMapExtend
set g_Demo(tMaxDetailLevel) 0
# The overall maximum detail level from s and t.
set g_Demo(overallMaxDetailLevel) 0
# Number of points in s direction.
set g_Demo(sNumPoints) 0
# Number of points in t direction.
set g_Demo(tNumPoints) 0
# FOV radius
set g_Demo(fovRadius) 10000.0
# Projection matrix.
set g_Demo(projection) [tcl3dVector GLfloat 16]
# Model view matrix.
set g_Demo(modelView) [tcl3dVector GLfloat 16]
# Texture to world space matrix.
set g_Demo(textureToWorld) [tcl3dVector GLfloat 16]
set g_Demo(textureToWorldNormal) [tcl3dVector GLfloat 16]
# World to texture space matrix.
set g_Demo(worldToTexture) [tcl3dVector GLfloat 16]
set g_Demo(worldToTextureNormal) [tcl3dVector GLfloat 16]
# Detail level at the beginning of the map.
set g_Demo(minimumDetailLevel) 4
# Additional detail level in the first pass. Adjust in GeometryPassOne max_vertices = 4^(firstPassDetailLevel+1)
set g_Demo(firstPassDetailLevel) 2
# Number of quadrants when going to the next detail level.
set g_Demo(quadrantStep) 2
set g_Demo(angle) 0.0
# A stop watch to get current time.
set g_Demo(stopWatch) [tcl3dNewSwatch]
tcl3dStartSwatch $g_Demo(stopWatch)
set g_Demo(lastTime) [tcl3dLookupSwatch $g_Demo(stopWatch)]
# 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 Min { a b } {
if { $a < $b } {
return $a
} else {
return $b
}
}
proc Animate {} {
global g_Demo
.fr.toglwin postredisplay
set g_Demo(animateId) [tcl3dAfterIdle Animate]
}
proc StartAnimation {} {
global g_Demo
if { ! [info exists g_Demo(animateId)] } {
Animate
tcl3dStartSwatch $g_Demo(stopWatch)
}
}
proc StopAnimation {} {
global g_Demo
if { [info exists g_Demo(animateId)] } {
after cancel $g_Demo(animateId)
unset g_Demo(animateId)
tcl3dStopSwatch $g_Demo(stopWatch)
}
}
# Function for initialization.
proc Init {} {
global g_Demo g_ViewData
# gl_Position will be transformed to the buffer
set transformVaryings "vertexTransform"
set g_ViewData(topView,camPos) [list 0.0 [expr 30000.0 * $g_Demo(metersToVirtualWorldScale)] 0.0 1.0]
set g_ViewData(topView,camDir) [list 0.0 -1.0 0.0]
set g_ViewData(topView,camUp) [list 0.0 0.0 -1.0]
set g_ViewData(topView,fov) 40.0
set g_ViewData(personView,camPos) [list 0.0 [expr 4700.0 * $g_Demo(metersToVirtualWorldScale)] 0.0 1.0]
set g_ViewData(personView,camDir) [list 0.0 0.0 -1.0]
set g_ViewData(personView,camUp) [list 0.0 1.0 0.0]
set g_ViewData(personView,fov) 60.0
set lightDir [list 1.0 1.0 1.0]
set g_Demo(activeView) "personView"
glPixelStorei GL_UNPACK_ALIGNMENT 1
set g_Demo(normalMapTexture) [tcl3dVector GLuint 1]
glGenTextures 1 $g_Demo(normalMapTexture)
glBindTexture GL_TEXTURE_RECTANGLE [$g_Demo(normalMapTexture) get 0]
set img [tcl3dReadImg [file join $g_Demo(scriptDir) $g_Demo(normalMap)]]
glTexImage2D GL_TEXTURE_RECTANGLE 0 [dict get $img format] \
[dict get $img width] [dict get $img height] 0 \
[dict get $img format] GL_UNSIGNED_BYTE [dict get $img data]
[dict get $img data] delete
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_MIN_FILTER $::GL_NEAREST
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_MAG_FILTER $::GL_NEAREST
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_WRAP_S $::GL_CLAMP_TO_EDGE
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_WRAP_T $::GL_CLAMP_TO_EDGE
set g_Demo(heightMapTexture) [tcl3dVector GLuint 1]
glGenTextures 1 $g_Demo(heightMapTexture)
glBindTexture GL_TEXTURE_RECTANGLE [$g_Demo(heightMapTexture) get 0]
set img [tcl3dReadImg [file join $g_Demo(scriptDir) $g_Demo(heightMap)]]
glTexImage2D GL_TEXTURE_RECTANGLE 0 [dict get $img format] \
[dict get $img width] [dict get $img height] 0 \
[dict get $img format] GL_UNSIGNED_BYTE [dict get $img data]
set sMapExtend [expr double([dict get $img width])]
set tMapExtend [expr double([dict get $img height])]
[dict get $img data] delete
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_MIN_FILTER $::GL_NEAREST
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_MAG_FILTER $::GL_NEAREST
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_WRAP_S $::GL_CLAMP_TO_EDGE
glTexParameteri GL_TEXTURE_RECTANGLE GL_TEXTURE_WRAP_T $::GL_CLAMP_TO_EDGE
set sMaxDetailLevel [expr int (floor (log ($sMapExtend) / log (2.0)))]
set tMaxDetailLevel [expr int (floor (log ($tMapExtend) / log (2.0)))]
set g_Demo(overallMaxDetailLevel) [Min $sMaxDetailLevel $tMaxDetailLevel]
if { $g_Demo(minimumDetailLevel) > $g_Demo(overallMaxDetailLevel) } {
puts [format "Detail level to high %d > %d" \
$g_Demo(minimumDetailLevel) $g_Demo(overallMaxDetailLevel)]
return false
}
if { $g_Demo(minimumDetailLevel) + $g_Demo(firstPassDetailLevel) > $g_Demo(overallMaxDetailLevel) } {
puts [format "First pass detail level to high %d > %d" \
[expr $g_Demo(minimumDetailLevel) + $g_Demo(firstPassDetailLevel)] $g_Demo(overallMaxDetailLevel)]
return false
}
set lev [expr pow (2.0, $g_Demo(overallMaxDetailLevel) - ($g_Demo(minimumDetailLevel) + $g_Demo(firstPassDetailLevel)))]
if { $lev > 32.0 } {
puts [format "Tessellation level to high %d > 32" [expr int ($lev)]]
return false
}
set detailStep [expr pow (2.0, [expr $g_Demo(overallMaxDetailLevel) - $g_Demo(minimumDetailLevel)])]
set g_Demo(sNumPoints) [expr int (ceil ($sMapExtend / $detailStep)) - 1]
set g_Demo(tNumPoints) [expr int (ceil ($tMapExtend / $detailStep)) - 1]
set detailStep2 [expr {0.5 + $detailStep / 2.0}]
for { set t 0 } { $t < $g_Demo(tNumPoints) } { incr t } {
for { set s 0 } { $s < $g_Demo(sNumPoints) } { incr s } {
lappend mapList [expr {$detailStep2 + $s * $detailStep}]
lappend mapList [expr {$detailStep2 + $t * $detailStep}]
lappend indList [expr {$t * $g_Demo(sNumPoints) + $s}]
}
}
set mapVec [tcl3dVectorFromList GLfloat $mapList]
set indVec [tcl3dVectorFromList GLuint $indList]
set mapVecSize [expr [llength $mapList] * [$mapVec elemsize]]
set indVecSize [expr [llength $indList] * [$indVec elemsize]]
#
# Transfering vertices and indices into GPU
#
# Pass one
# Generating vertex array object and binding to it.
set g_Demo(vaoPassOne) [tcl3dVector GLuint 1]
glGenVertexArrays 1 $g_Demo(vaoPassOne)
glBindVertexArray [$g_Demo(vaoPassOne) get 0]
# Generating the vertices buffer and binding to it.
set g_Demo(verticesBufferPassOne) [tcl3dVector GLuint 1]
glGenBuffers 1 $g_Demo(verticesBufferPassOne)
glBindBuffer GL_ARRAY_BUFFER [$g_Demo(verticesBufferPassOne) get 0]
# Transfering the vertices.
glBufferData GL_ARRAY_BUFFER $mapVecSize $mapVec GL_STATIC_DRAW
# Generating the indices buffer and binding to it.
set g_Demo(indicesBufferPassOne) [tcl3dVector GLuint 1]
glGenBuffers 1 $g_Demo(indicesBufferPassOne)
glBindBuffer GL_ELEMENT_ARRAY_BUFFER [$g_Demo(indicesBufferPassOne) get 0]
# Transfering the indices.
glBufferData GL_ELEMENT_ARRAY_BUFFER $indVecSize $indVec GL_STATIC_DRAW
# First 0 is the location = 0
glVertexAttribPointer 0 2 GL_FLOAT GL_FALSE 0 "NULL"
# Enable location = 0
glEnableVertexAttribArray 0
# Pass two.
# Generating vertex array object and binding to it.
set g_Demo(vaoPassTwo) [tcl3dVector GLuint 1]
glGenVertexArrays 1 $g_Demo(vaoPassTwo)
glBindVertexArray [$g_Demo(vaoPassTwo) get 0]
# Generating the vertices buffer and binding to it.
set g_Demo(verticesBufferPassTwo) [tcl3dVector GLuint 1]
glGenBuffers 1 $g_Demo(verticesBufferPassTwo)
glBindBuffer GL_ARRAY_BUFFER [$g_Demo(verticesBufferPassTwo) get 0]
# Reserving space for the incoming vertices.
glBufferData GL_ARRAY_BUFFER \
[expr {$g_Demo(sNumPoints) * $g_Demo(tNumPoints) * \
int (pow (4, $g_Demo(firstPassDetailLevel) + 1)) * 2 * [$mapVec elemsize]}] "NULL" GL_STATIC_DRAW
# First 0 is the location = 0
glVertexAttribPointer 0 2 GL_FLOAT GL_FALSE 0 "NULL"
# Enable location = 0
glEnableVertexAttribArray 0
$mapVec delete
$indVec delete
set g_Demo(colorMapTexture) [tcl3dVector GLuint 1]
glGenTextures 1 $g_Demo(colorMapTexture)
glBindTexture GL_TEXTURE_2D [$g_Demo(colorMapTexture) get 0]
set img [tcl3dReadImg [file join $g_Demo(scriptDir) $g_Demo(colorMap)]]
glTexImage2D GL_TEXTURE_2D 0 [dict get $img format] \
[dict get $img width] [dict get $img height] 0 \
[dict get $img format] GL_UNSIGNED_BYTE [dict get $img data]
[dict get $img data] delete
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $::GL_REPEAT
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $::GL_REPEAT
# Creating the shader program.
# Pass one.
# Load the source of the vertex shader.
set vertexSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "VertexPassOne.vs"]]
# Load the source of the geometry shader.
set geometrySource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "GeometryPassOne.gs"]]
# Load the source of the fragment shader.
set fragmentSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "FragmentPassOne.fs"]]
# Compile and ...
set g_Demo(shaderProgramPassOne) [tcl3dOglCompileProgram $vertexSource "" "" $geometrySource $fragmentSource]
set programPassOne [dict get $g_Demo(shaderProgramPassOne) program]
# ... add the transform variable ...
glTransformFeedbackVaryings $programPassOne 1 [list $transformVaryings] GL_SEPARATE_ATTRIBS
# ... and link the program
tcl3dOglLinkProgram $g_Demo(shaderProgramPassOne)
set g_Demo(halfDetailStepLocationPassOne) [glGetUniformLocation $programPassOne "halfDetailStep"]
set g_Demo(firstPassDetailLevelLocationPassOne) [glGetUniformLocation $programPassOne "firstPassDetailLevel"]
set g_Demo(positionTextureLocationPassOne) [glGetUniformLocation $programPassOne "positionTexture"]
set g_Demo(fovRadiusLocationPassOne) [glGetUniformLocation $programPassOne "fovRadius"]
set g_Demo(leftNormalTextureLocationPassOne) [glGetUniformLocation $programPassOne "leftNormalTexture"]
set g_Demo(rightNormalTextureLocationPassOne) [glGetUniformLocation $programPassOne "rightNormalTexture"]
set g_Demo(backNormalTextureLocationPassOne) [glGetUniformLocation $programPassOne "backNormalTexture"]
# Pass two.
# Load the source of the vertex shader.
set vertexSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "VertexPassTwo.vs"]]
# Load the source of the control shader.
set controlSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "ControlPassTwo.tcs"]]
# Load the source of the evaluation shader.
set evaluationSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "EvaluationPassTwo.tes"]]
# Load the source of the geometry shader.
set geometrySource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "GeometryPassTwo.gs"]]
# Load the source of the fragment shader.
set fragmentSource [tcl3dOglReadShaderFile [file join $g_Demo(scriptDir) "FragmentPassTwo.fs"]]
set g_Demo(shaderProgramPassTwo) [tcl3dOglBuildProgram $vertexSource $controlSource $evaluationSource \
$geometrySource $fragmentSource]
set programPassTwo [dict get $g_Demo(shaderProgramPassTwo) program]
# Get the location of the matrix.
set g_Demo(tmvpLocationPassTwo) [glGetUniformLocation $programPassTwo "TMVP"]
set g_Demo(positionTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "positionTexture"]
set g_Demo(maxTessellationLevelLocationPassTwo) [glGetUniformLocation $programPassTwo "maxTessellationLevel"]
set g_Demo(quadrantStepLocationPassTwo) [glGetUniformLocation $programPassTwo "quadrantStep"]
set g_Demo(leftNormalTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "leftNormalTexture"]
set g_Demo(rightNormalTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "rightNormalTexture"]
set g_Demo(backNormalTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "backNormalTexture"]
set g_Demo(normalMapTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "normalMapTexture"]
set g_Demo(heightMapTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "heightMapTexture"]
set g_Demo(colorMapTextureLocationPassTwo) [glGetUniformLocation $programPassTwo "colorMapTexture"]
set g_Demo(lightDirLocationPassTwo) [glGetUniformLocation $programPassTwo "lightDir"]
# One time GL settings.
glPatchParameteri GL_PATCH_VERTICES 4
set g_Demo(transformFeedbackQuery) [tcl3dVector GLuint 1]
glGenQueries 1 $g_Demo(transformFeedbackQuery)
# Matrix calculations
tcl3dMatfIdentity $g_Demo(textureToWorld)
tcl3dMatfIdentity $g_Demo(textureToWorldNormal)
tcl3dScalef \
[expr {$g_Demo(horizontalPixelSpacing) * $g_Demo(metersToVirtualWorldScale)}] \
[expr {$g_Demo(verticalPixelRange) * $g_Demo(metersToVirtualWorldScale)}] \
[expr {$g_Demo(horizontalPixelSpacing) * $g_Demo(metersToVirtualWorldScale)}] \
$g_Demo(textureToWorld)
tcl3dScalef 1.0 1.0 -1.0 $g_Demo(textureToWorld)
tcl3dScalef 1.0 1.0 -1.0 $g_Demo(textureToWorldNormal)
tcl3dTranslatef [expr {-$sMapExtend / 2.0}] 0.0 [expr {-$tMapExtend / 2.0}] $g_Demo(textureToWorld)
tcl3dMatfInvert $g_Demo(textureToWorld) $g_Demo(worldToTexture)
tcl3dMatfInvert $g_Demo(textureToWorldNormal) $g_Demo(worldToTextureNormal)
# Pass One
glUseProgram $programPassOne
glUniform1f $g_Demo(halfDetailStepLocationPassOne) [expr {$detailStep / 2.0}]
glUniform1ui $g_Demo(firstPassDetailLevelLocationPassOne) $g_Demo(firstPassDetailLevel)
glUniform1f $g_Demo(fovRadiusLocationPassOne) \
[expr {$g_Demo(fovRadius) / $g_Demo(horizontalPixelSpacing) * $g_Demo(metersToVirtualWorldScale)}]
# Pass Two
glUseProgram $programPassTwo
glUniform1ui $g_Demo(maxTessellationLevelLocationPassTwo) \
[expr {$g_Demo(overallMaxDetailLevel) - ($g_Demo(minimumDetailLevel) + $g_Demo(firstPassDetailLevel))}]
glUniform1i $g_Demo(quadrantStepLocationPassTwo) $g_Demo(quadrantStep)
glActiveTexture GL_TEXTURE0
glUniform1i $g_Demo(heightMapTextureLocationPassTwo) 0
glBindTexture GL_TEXTURE_RECTANGLE [$g_Demo(heightMapTexture) get 0]
glActiveTexture GL_TEXTURE1
glUniform1i $g_Demo(colorMapTextureLocationPassTwo) 1
glBindTexture GL_TEXTURE_2D [$g_Demo(colorMapTexture) get 0]
glActiveTexture GL_TEXTURE2
glUniform1i $g_Demo(normalMapTextureLocationPassTwo) 2
glBindTexture GL_TEXTURE_RECTANGLE [$g_Demo(normalMapTexture) get 0]
glActiveTexture GL_TEXTURE0
glUniform3fv $g_Demo(lightDirLocationPassTwo) 1 $lightDir
return true
}
proc CreateCallback { toglwin } {
glClearColor 0.0 0.0 0.0 0.0
glClearDepth 1.0
glEnable GL_DEPTH_TEST
glEnable GL_CULL_FACE
}
proc ReshapeCallback { toglwin { w -1 } { h -1 } } {
global g_Demo g_ViewData
set w [$toglwin width]
set h [$toglwin height]
set g_Demo(winWidth) $w
set g_Demo(winHeight) $h
glViewport 0 0 $w $h
if { ! $g_Demo(haveNeededVersion) } {
return
}
set activeView $g_Demo(activeView)
tcl3dLookAt \
[lindex $g_ViewData($activeView,camPos) 0] \
[lindex $g_ViewData($activeView,camPos) 1] \
[lindex $g_ViewData($activeView,camPos) 2] \
[expr {[lindex $g_ViewData($activeView,camPos) 0] + [lindex $g_ViewData($activeView,camDir) 0]}] \
[expr {[lindex $g_ViewData($activeView,camPos) 1] + [lindex $g_ViewData($activeView,camDir) 1]}] \
[expr {[lindex $g_ViewData($activeView,camPos) 2] + [lindex $g_ViewData($activeView,camDir) 2]}] \
[lindex $g_ViewData($activeView,camUp) 0] \
[lindex $g_ViewData($activeView,camUp) 1] \
[lindex $g_ViewData($activeView,camUp) 2] \
$g_Demo(modelView)
tcl3dPerspective $g_ViewData($activeView,fov) [expr {double($w)/double($h) }] 1.0 1000000.0 $g_Demo(projection)
glUseProgram [dict get $g_Demo(shaderProgramPassTwo) program]
set TMVP [tcl3dVector GLfloat 16]
tcl3dMatfIdentity $TMVP
tcl3dMatfMult $TMVP $g_Demo(projection) $TMVP
tcl3dMatfMult $TMVP $g_Demo(modelView) $TMVP
tcl3dMatfMult $TMVP $g_Demo(textureToWorld) $TMVP
glUniformMatrix4fv $g_Demo(tmvpLocationPassTwo) 1 GL_FALSE [tcl3dVectorToList $TMVP 16]
$TMVP delete
}
proc ToggleView { toglwin } {
global g_Demo
set g_Demo(topViewActive) [expr ! $g_Demo(topViewActive)]
if { $g_Demo(topViewActive) } {
set g_Demo(activeView) "personView"
} else {
set g_Demo(activeView) "topView"
}
tcl3dPerspective 40.0 [expr {double($g_Demo(winWidth))/double($g_Demo(winHeight)) }] \
1.0 1000000.0 $g_Demo(projection)
$toglwin postredisplay
}
proc ToggleAnimation { toglwin } {
global g_Demo
set g_Demo(animationOn) [expr ! $g_Demo(animationOn)]
$toglwin postredisplay
}
proc ToggleWireframe { toglwin } {
global g_Demo
set g_Demo(filled) [expr ! $g_Demo(filled)]
if { $g_Demo(filled) } {
glPolygonMode GL_FRONT_AND_BACK GL_LINE
} else {
glPolygonMode GL_FRONT_AND_BACK GL_FILL
}
$toglwin postredisplay
}
proc DisplayCallback { toglwin } {
global g_Demo g_ViewData
if { ! $g_Demo(haveNeededVersion) } {
$toglwin swapbuffer
return
}
set curTime [tcl3dLookupSwatch $g_Demo(stopWatch)]
set elapsedTime [expr $curTime - $g_Demo(lastTime)]
set g_Demo(lastTime) $curTime
# Animation update
set PI2 [expr {2.0 * 3.1415926535897932384626433832795 }]
lset g_ViewData(personView,camPos) 0 [expr -cos($PI2 * $g_Demo(angle)/$g_Demo(turnDuration)) * $g_Demo(radius) * $g_Demo(metersToVirtualWorldScale)]
lset g_ViewData(personView,camPos) 2 [expr -sin($PI2 * $g_Demo(angle)/$g_Demo(turnDuration)) * $g_Demo(radius) * $g_Demo(metersToVirtualWorldScale)]
lset g_ViewData(personView,camDir) 0 [expr sin($PI2 * $g_Demo(angle)/$g_Demo(turnDuration))]
lset g_ViewData(personView,camDir) 2 [expr -cos($PI2 * $g_Demo(angle)/$g_Demo(turnDuration))]
if { $g_Demo(animationOn) } {
set g_Demo(angle) [expr $g_Demo(angle) + $elapsedTime]
}
set activeView $g_Demo(activeView)
tcl3dLookAt \
[lindex $g_ViewData($activeView,camPos) 0] \
[lindex $g_ViewData($activeView,camPos) 1] \
[lindex $g_ViewData($activeView,camPos) 2] \
[expr {[lindex $g_ViewData($activeView,camPos) 0] + [lindex $g_ViewData($activeView,camDir) 0]}] \
[expr {[lindex $g_ViewData($activeView,camPos) 1] + [lindex $g_ViewData($activeView,camDir) 1]}] \
[expr {[lindex $g_ViewData($activeView,camPos) 2] + [lindex $g_ViewData($activeView,camDir) 2]}] \
[lindex $g_ViewData($activeView,camUp) 0] \
[lindex $g_ViewData($activeView,camUp) 1] \
[lindex $g_ViewData($activeView,camUp) 2] \
$g_Demo(modelView)
glUseProgram [dict get $g_Demo(shaderProgramPassTwo) program]
set TMVP [tcl3dVector GLfloat 16]
tcl3dMatfIdentity $TMVP
tcl3dMatfMult $TMVP $g_Demo(projection) $TMVP
tcl3dMatfMult $TMVP $g_Demo(modelView) $TMVP
tcl3dMatfMult $TMVP $g_Demo(textureToWorld) $TMVP
glUniformMatrix4fv $g_Demo(tmvpLocationPassTwo) 1 GL_FALSE [tcl3dVectorToList $TMVP 16]
$TMVP delete
# Position
set flatPos [tcl3dVector GLfloat 3]
set positionTexture [tcl3dVector GLfloat 3]
set directionTexture [tcl3dVector GLfloat 3]
set leftNormal [tcl3dVector GLfloat 3]
set leftNormalTexture [tcl3dVector GLfloat 3]
set rightNormal [tcl3dVector GLfloat 3]
set rightNormalTexture [tcl3dVector GLfloat 3]
set backNormal [tcl3dVector GLfloat 3]
set backNormalTexture [tcl3dVector GLfloat 3]
set rotationMatrix [tcl3dVector GLfloat 16]
$flatPos set 0 [lindex $g_ViewData(personView,camPos) 0]
$flatPos set 1 0.0
$flatPos set 2 [lindex $g_ViewData(personView,camPos) 2]
tcl3dMatfTransformPoint $flatPos $g_Demo(worldToTexture) $positionTexture
# Direction
tcl3dMatfTransformVector $flatPos $g_Demo(worldToTexture) $directionTexture
set camDir [tcl3dVectorFromList GLfloat $g_ViewData(personView,camDir)]
# Left normal of field ov view
tcl3dMatfIdentity $rotationMatrix
tcl3dRotatef [expr $g_ViewData(personView,fov) * ($g_Demo(winWidth) / $g_Demo(winHeight)) / 2.0 + 90.0] 0.0 1.0 0.0 $rotationMatrix
tcl3dMatfTransformVector $camDir $rotationMatrix $leftNormal
tcl3dMatfTransformVector $leftNormal $g_Demo(worldToTextureNormal) $leftNormalTexture
# Right normal of field ov view
tcl3dMatfIdentity $rotationMatrix
tcl3dRotatef [expr -$g_ViewData(personView,fov) * ($g_Demo(winWidth) / $g_Demo(winHeight)) / 2.0 - 90.0] 0.0 1.0 0.0 $rotationMatrix
tcl3dMatfTransformVector $camDir $rotationMatrix $rightNormal
tcl3dMatfTransformVector $rightNormal $g_Demo(worldToTextureNormal) $rightNormalTexture
# Back normal of field ov views
tcl3dMatfIdentity $rotationMatrix
tcl3dRotatef 180.0 0.0 1.0 0.0 $rotationMatrix
tcl3dMatfTransformVector $camDir $rotationMatrix $backNormal
tcl3dMatfTransformVector $backNormal $g_Demo(worldToTextureNormal) $backNormalTexture
$camDir delete
# OpenGL stuff
glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT]
# Pass one.
glEnable GL_RASTERIZER_DISCARD
glUseProgram [dict get $g_Demo(shaderProgramPassOne) program]
glUniform4fv $g_Demo(positionTextureLocationPassOne) 1 [tcl3dVectorToList $positionTexture 4]
glUniform3fv $g_Demo(leftNormalTextureLocationPassOne) 1 [tcl3dVectorToList $leftNormalTexture 3]
glUniform3fv $g_Demo(rightNormalTextureLocationPassOne) 1 [tcl3dVectorToList $rightNormalTexture 3]
glUniform3fv $g_Demo(backNormalTextureLocationPassOne) 1 [tcl3dVectorToList $backNormalTexture 3]
glBindVertexArray [$g_Demo(vaoPassOne) get 0]
glBindBufferBase GL_TRANSFORM_FEEDBACK_BUFFER 0 [$g_Demo(verticesBufferPassTwo) get 0]
glBeginQuery GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN [$g_Demo(transformFeedbackQuery) get 0]
glBeginTransformFeedback GL_POINTS
glDrawElements GL_POINTS [expr $g_Demo(sNumPoints) * $g_Demo(tNumPoints)] GL_UNSIGNED_INT "NULL"
glEndTransformFeedback
glEndQuery GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
glDisable GL_RASTERIZER_DISCARD
# Pass two
glUseProgram [dict get $g_Demo(shaderProgramPassTwo) program]
glUniform4fv $g_Demo(positionTextureLocationPassTwo) 1 [tcl3dVectorToList $positionTexture 4]
glUniform3fv $g_Demo(leftNormalTextureLocationPassTwo) 1 [tcl3dVectorToList $leftNormalTexture 3]
glUniform3fv $g_Demo(rightNormalTextureLocationPassTwo) 1 [tcl3dVectorToList $rightNormalTexture 3]
glUniform3fv $g_Demo(backNormalTextureLocationPassTwo) 1 [tcl3dVectorToList $backNormalTexture 3]
glBindVertexArray [$g_Demo(vaoPassTwo) get 0]
set primitivesWritten [tcl3dVector GLuint 1]
glGetQueryObjectuiv [$g_Demo(transformFeedbackQuery) get 0] GL_QUERY_RESULT $primitivesWritten
glDrawArrays GL_PATCHES 0 [$primitivesWritten get 0]
$primitivesWritten delete
$flatPos delete
$positionTexture delete
$directionTexture delete
$leftNormal delete
$leftNormalTexture delete
$rightNormal delete
$rightNormalTexture delete
$backNormal delete
$backNormalTexture delete
$rotationMatrix delete
$toglwin swapbuffer
}
proc Cleanup {} {
global g_Demo g_ViewData
# Pass one.
if { [info exists g_Demo(verticesBufferPassOne)] } {
glDeleteBuffers 1 [$g_Demo(verticesBufferPassOne) get 0]
$g_Demo(verticesBufferPassOne) delete
}
if { [info exists g_Demo(indicesBufferPassOne)] } {
glDeleteBuffers 1 [$g_Demo(indicesBufferPassOne) get 0]
$g_Demo(indicesBufferPassOne) delete
}
if { [info exists g_Demo(vaoPassOne)] } {
glDeleteVertexArrays 1 [$g_Demo(vaoPassOne) get 0]
$g_Demo(vaoPassOne) delete
}
if { [info exists g_Demo(shaderProgramPassOne)] } {
tcl3dOglDestroyProgram $g_Demo(shaderProgramPassOne)
}
# Pass two.
if { [info exists g_Demo(verticesBufferPassTwo)] } {
glDeleteBuffers 1 [$g_Demo(verticesBufferPassTwo) get 0]
$g_Demo(verticesBufferPassTwo) delete
}
if { [info exists g_Demo(vaoPassTwo)] } {
glDeleteVertexArrays 1 [$g_Demo(vaoPassTwo) get 0]
$g_Demo(vaoPassTwo) delete
}
if { [info exists g_Demo(normalMapTexture)] } {
glDeleteTextures 1 [$g_Demo(normalMapTexture) get 0]
$g_Demo(normalMapTexture) delete
}
if { [info exists g_Demo(heightMapTexture)] } {
glDeleteTextures 1 [$g_Demo(heightMapTexture) get 0]
$g_Demo(heightMapTexture) delete
}
if { [info exists g_Demo(colorMapTexture)] } {
glDeleteTextures 1 [$g_Demo(colorMapTexture) get 0]
$g_Demo(colorMapTexture) delete
}
if { [info exists g_Demo(shaderProgramPassTwo)] } {
tcl3dOglDestroyProgram $g_Demo(shaderProgramPassTwo)
}
if { [info exists g_Demo(transformFeedbackQuery)] } {
glDeleteQueries 1 [$g_Demo(transformFeedbackQuery) get 0]
$g_Demo(transformFeedbackQuery) delete
}
# Unset all global variables.
# Needed when running the demo in the Tcl3D presentation framework.
foreach var [info globals g_*] {
uplevel #0 unset $var
}
}
# Put all exit related code here.
proc ExitProg {} {
exit
}
# Create the OpenGL window and some Tk helper widgets.
proc CreateWindow {} {
global g_Demo
frame .fr
pack .fr -expand 1 -fill both
# Create a Togl window with an OpenGL core profile using version 3.3.
# Reshape and Display callbacks are configured later after knowing if
# the needed OpenGL profile version is available.
togl .fr.toglwin -width $g_Demo(winWidth) -height $g_Demo(winHeight) \
-double true -depth true \
-createcommand CreateCallback \
-coreprofile true -major 4 -minor 1
set g_Demo(haveNeededVersion) true
set numRows 4
set haveGL4 [tcl3dOglHaveVersion 4]
if { ! $haveGL4 } {
set msgStr [format \
"Demo needs core profile 4.1. Only have GL version %s" \
[tcl3dOglGetVersion]]
set g_Demo(haveNeededVersion) false
incr numRows
} else {
set profile [tcl3dOglGetProfile .fr.toglwin]
if { [dict get $profile "coreprofile"] != true } {
set msgStr [format \
"Demo needs core profile 4.1. Only have compatibility profile %d.%d" \
[dict get $profile "major"] \
[dict get $profile "minor"]]
incr numRows
}
}
if { $g_Demo(haveNeededVersion) } {
# If OpenGL 4.1 or higher is available, initialize the buffers.
Init
}
# Now attach the Reshape and Display callbacks to the Togl window.
.fr.toglwin configure \
-reshapecommand ReshapeCallback \
-displaycommand DisplayCallback
listbox .fr.usage -font $g_Demo(listFont) -height $numRows
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: Nopper's core profile tutorials (Example 13 - Terrain Rendering)"
# Watch for Esc key and Quit messages
wm protocol . WM_DELETE_WINDOW "ExitProg"
bind . <Key-Escape> "ExitProg"
bind . <Key-v> "ToggleView .fr.toglwin"
bind . <Key-a> "ToggleAnimation .fr.toglwin"
bind . <Key-w> "ToggleWireframe .fr.toglwin"
.fr.usage insert end "Key-Escape Exit"
.fr.usage insert end "Key-v Toggle view"
.fr.usage insert end "Key-a Toggle animation"
.fr.usage insert end "Key-w Toggle wireframe"
if { [info exists msgStr] } {
.fr.usage insert end $msgStr
.fr.usage itemconfigure end -background red
} else {
.fr.usage configure -state disabled
}
}
CreateWindow
ReshapeCallback .fr.toglwin
PrintInfo [tcl3dOglGetInfoString]
if { [file tail [info script]] eq [file tail $::argv0] } {
# If started directly from tclsh or wish, then start animation.
update
StartAnimation
}
|