[HOME][CONTENTS][DOWNLOAD][PREV][NEXT]


3D IMAGE RENDERING

A Textured Globe.  The following are two textured globe objects: the left one was rendered with a GLW widget and the right one was rendered with a glw image displayed with a canvas widget.  The attached source code highlights a architecture of a molular GUI implementation for scriptive OpenGL rendering with both a GLW widget and a glw image.  It shows how a token of a pointer created by gluNewQuadric is returned as a Tcl string and then passed into a suite of gluQuadric functions via Tcl scripts for quadric primitive rendering.  It also shows how to use a Tcl command glphoto to import texture data from a Tk Photo image.

 

A textured globe rendered 
with a GLW widget
A textured globe rendered
with a glw image displayed
in a canvas widget
#
# Copyright(c) 1999-2001, Chengye Mao, email: chengye.geo@yahoo.com
#
# globe - To render a textured 3D earth globe with a GLW 
#      widget/image. The image is loaded into a local variable
#      from a Tk photo using a function glphoto. Functions
#      glTexParameter, glTexEnv, gluBuild2DMipmaps are used to prepare
#      texture. After the texture is set up, the local image variable
#      is freed. Functions gluQuadricDrawStyle, gluQuadricNormals
#      gluQuadricTexture, gluSphere are used to create the textured
#      globe.
#
# Binding of mouse motion with left-button pressed
#      rotate the globe
#
# Binding of keypress
#      Escape - destroy the GLW widget/image
#      Q/q    - stop or start rotation
#      "w"    - display in a wired mode
#      "W"    - display in a filled mode
#
# Procedures:
#     globe.init         - initialize
#     globe.texture      - texture set up
#     globe.sphere       - prepare a textured globe
#     globe.display      - display the globe
#     globe.reshape     - configurate the GLW widget/image
#     globe.mouse        - handle mouse button press
#     globe.motion       - handle mouse motion
#     globe.keypress     - handle key press
#     globe.create       - entry to create a GLW widget.
#
# Procedures to wrap a GLW image into a hosting widget:
#     globe.img          - create a GLW image for rendering
#     globe.img.keypress - handle key press in a hosting widget
#     globe.img.config   - configure a GLW image with its hosting widget
#     globe.bind         - binding a hosting widget to globe proccedures
#     globecanv.create   - entry to create a canvas-hosted GLW image
#

proc globe.init w {
    global gimgHome 
    set old [glw current $w]

    GLfloat ambient_light {0.35 0.4 0.45 1.0}
    GLfloat source_light {0.9 0.85 0.8 1.0}
    GLfloat light_pos {5.5 1 0 1}
    GLfloat angle
    GLfloat angle2
    GLint moving 
    GLint startx
    GLint starty

    # Set up a simple lighting model
    glEnable GL_LIGHTING
    glLightModel GL_LIGHT_MODEL_AMBIENT ambient_light
    glLight GL_LIGHT0 GL_DIFFUSE source_light
    glLight GL_LIGHT0 GL_POSITION light_pos
    glEnable GL_LIGHT0

    # Enable material properties for lighting
    glEnable GL_COLOR_MATERIAL
    glColorMaterial GL_FRONT GL_AMBIENT_AND_DIFFUSE

    glEnable GL_TEXTURE_2D
    glPixelStore GL_UNPACK_ALIGNMENT 1

    set imgFileName [file join $gimgHome gif globe3t.ppm]

    globe.texture $imgFileName 3 GL_RGB GL_LINEAR

    glEnable GL_CULL_FACE
    glClearColor 0 0 0 0
    glw current $old
}
proc globe.texture {fileName depth colorType filterType} {
    image create photo globe -file $fileName
    set width [image width globe]
    set height [image height globe]
    glphoto texImage globe

    # Set Filtering type
    glTexParameter GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $filterType
    glTexParameter GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $filterType

    # Set Texture Environment
    glTexEnv GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE GL_MODULATE

    # Build Mipmaps
    gluBuild2DMipmaps GL_TEXTURE_2D $depth $width $height \
        $colorType GL_UNSIGNED_BYTE texImage

    # Free up the array
    gldel texImage
}
proc globe.sphere {} {
    glPushMatrix
    glRotate 90 1 0 0
    glColor 1 1 1 1

    set q [gluNewQuadric]

    gluQuadricDrawStyle $q GLU_FILL
    gluQuadricNormals $q GLU_SMOOTH
    gluQuadricTexture $q GL_TRUE

    gluSphere $q 1.0 24 24
    gluDeleteQuadric $q

    glPopMatrix
}
proc globe.display w {
    set old [glw current $w]
    glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
    glClear GL_COLOR_BUFFER_BIT
    glLight GL_LIGHT0 GL_POSITION light_pos

    glPushMatrix
    glTranslate 0 0 -4
    glRotate angle2 1 0 0
    glRotate angle 0 1 0
    globe.sphere
    glPopMatrix
    glFlush
    glw draw
    glw current $old
}
proc globe.reshape {w width height} {
    set old [glw current $w]
    glViewport 0 0 $width $height
    glMatrixMode GL_PROJECTION
    glLoadIdentity
    if {$height == 0} {
        gluPerspective 45 $width 1.0 2000.0
    } else {
        gluPerspective 45 [expr $width/double($height)] 1.0 2000.0
    }
    glMatrixMode GL_MODELVIEW
    glLoadIdentity
    glw current $old
}
proc globe.mouse {w state x y} {
    set old [glw current $w]
    if {$state == "BUTTON_DOWN"} {
        glset moving 1
        glset startx $x
        glset starty $y
    }

    if {$state == "BUTTON_UP"} {
        glset moving 0
    }
    glw current $old
}
proc globe.motion {w x y} {
    set old [glw current $w]
    if {[glv moving]} {
        glset angle [expr [glv angle] + $x - [glv startx]]
        glset angle2 [expr [glv angle2] + $y - [glv starty]]
        glset startx $x
        glset starty $y
        globe.display $w
    }
    glw current $old
}
proc globe.rotate w {
    set old [glw current $w]
    glset angle [expr [glv angle] + 1.0]
    if { [glv angle] == 360.0 } {
        glset angle 0
    }
    globe.display $w
    glw current $old
}
proc globe.keypress {w keycode keysym} {
    set old [glw current $w]
    switch $keysym {
        "Escape" { glw delete $w}
        "w" { glPolygonMode GL_FRONT_AND_BACK GL_LINE }
        "W" { glPolygonMode GL_FRONT_AND_BACK GL_FILL }
        "q" -
        "Q" {globe.queue $w}
    }
    catch {
        globe.display $w
        glw current $old
    }
}
proc globe.create w {
    glw $w -width 256 -height 256
    globe.init $w

    bind $w <Configure>     "globe.reshape $w %w %h"
    bind $w <Expose>        "globe.display $w"
    bind $w <ButtonRelease> "globe.mouse $w BUTTON_UP %x %y"
    bind $w <ButtonPress>   "globe.mouse $w BUTTON_DOWN %x %y"
    bind $w <Motion>        "globe.motion $w %x %y"
    bind $w <KeyPress>      "globe.keypress $w %k %K"

    focus $w
    return $w
}
proc globe.queue w {
    set old [glw current $w]
    if [catch "glv qid"] {
        GLint qid [queue.put "globe.rotate $w"]
    } else {
        queue.remove [glv qid]
        gldel qid
    }
    glw current $old 
}
proc globe.img img {
    image create glw $img -width 256 -height 256
    globe.init $img
    globe.reshape $img 256 256
    globe.display $img
    return $img
}
proc globe.img.keypress {w img keycode keysym} {
    switch $keysym {
        "Escape" {destroy $w}
        default {globe.keypress $img $keycode $keysym}
    }
}
proc globe.img.config {w img wwd wht} {
    set bd [$w cget -bd]
    set width [expr $wwd - 2 * $bd]
    set height [expr $wht - 2 * $bd]
    $img config -width $width -height $height
    globe.reshape $img $width $height
    globe.display $img
}
proc globe.img.bind {w img} {
    bind $w <Configure>     "globe.img.config $w $img %w %h"
    bind $w <ButtonRelease> "globe.mouse $img BUTTON_UP %x %y"
    bind $w <ButtonPress>   "globe.mouse $img BUTTON_DOWN %x %y"
    bind $w <Motion>        "globe.motion $img %x %y"
    bind $w <KeyPress>      "globe.img.keypress $w $img %k %K" 
    focus $w
}
proc globecanv.create canv {
    canvas $canv -width 256 -height 256
    $canv create image 0 0 -image [globe.img globe$canv] -anchor nw
    $canv create text 50 50 -fill red -anchor nw \
        -text "GLW Image - Rotating Globe"
    globe.img.bind $canv globe$canv
    bind $canv <Destroy> "image delete globe$canv"
    return $canv
}
 

[HOME][CONTENTS][DOWNLOAD] 1