# Lesson46.tcl
#
# NeHe & MainRoach's FSAA Tutorial
#
# This Code Was Created By Jeff Molofee 2001
# and Colt McAnlis ( MainRoach ).
# 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/13
# See www.tcl3d.org for the Tcl3D extension.
#
# This demo uses the multisampling options built into tcl3dTogl starting
# from version 0.3.2.
# Another way to set the number of samples is via the driver specific GUI under
# Windows, or by setting the environment variable __GL_FSAA_MODE under Linux.

package require tcl3d

# Font to be used in the Tk listbox.
set gDemo(listFont) {-family {Courier} -size 10}

# Display mode.
set gDemo(fullScreen) false

# Window size.
set gDemo(winWidth)  640
set gDemo(winHeight) 480

set gDemo(doMulti)  1
set gDemo(angle)    0.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 { $::gDemo(fullScreen) } {
        SetFullScreenMode .
        set ::gDemo(fullScreen) false
    } else {
        SetWindowMode . $::gDemo(winWidth) $::gDemo(winHeight)
        set ::gDemo(fullScreen) true
    }
}

# Print information about the multisampling state into last row of usage list.
proc PrintFSAAInfo {} {
    if { ! [winfo exists .fr.usage] } {
        return
    }

    .fr.usage configure -state normal
    .fr.usage delete end
    if { $::gDemo(doMulti) } {
        set sbufs   [tcl3dOglGetIntegerState GL_SAMPLE_BUFFERS]
        set samples [tcl3dOglGetIntegerState GL_SAMPLES]
        if { $sbufs > 0 } {
            .fr.usage insert end "Multisampling: ON (Number of samples: $samples)"
        } else {
            .fr.usage insert end "Multisampling: ON (No sample buffer available)"
        }
    } else {
        .fr.usage insert end "Multisampling: OFF"
    }
    .fr.usage configure -state disabled
}

proc ToggleMultisampling { toglwin } {
    set ::gDemo(doMulti) [expr ! $::gDemo(doMulti)]
    PrintFSAAInfo
    $toglwin postredisplay
}

# 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 50.0 [expr double($w)/double($h)] 5 2000

    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 } {
    global gDemo

    set gDemo(angle) 0.0

    glShadeModel GL_SMOOTH                  ; # Enable Smooth Shading
    glClearColor 0.0 0.0 0.0 0.5            ; # Black Background
    glEnable GL_DEPTH_TEST                  ; # Enables Depth Testing
}

proc Animate {} {
    .fr.toglwin postredisplay
    set ::animateId [tcl3dAfterIdle Animate]
}

proc StartAnimation {} {
    if { [info commands .fr.toglwin] eq "" } {
        return
    }
    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 } {
    global gDemo

    if { $gDemo(doMulti) } {
        glEnable GL_MULTISAMPLE_ARB     ; # Enable Our Multisampling
    }

    # 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]

    glLoadIdentity                      ; # Reset The Current Modelview Matrix

    for { set i -10 } { $i < 10 } { incr i } {
        for { set j -10 } { $j < 10 } { incr j } {
            glPushMatrix
            glTranslatef [expr {$i*2.0}] [expr {$j*2.0}] -5.0
            glRotatef $gDemo(angle) 0.0 0.0 1.0
                glBegin GL_QUADS
                glColor3f 1.0 0.0 0.0 ; glVertex3f $i $j 0.0
                glColor3f 0.0 1.0 0.0 ; glVertex3f [expr {$i + 2.0}] $j 0.0
                glColor3f 0.0 0.0 1.0 ; glVertex3f [expr {$i + 2.0}] [expr {$j + 2.0}] 0.0
                glColor3f 1.0 1.0 1.0 ; glVertex3f $i [expr {$j + 2.0}] 0.0
                glEnd
            glPopMatrix
        }
    }

    if { [info exists ::animateId] } {
        set gDemo(angle) [expr {$gDemo(angle) + 0.1}]
    }

    glFlush
    $toglwin swapbuffers

    if { $gDemo(doMulti) } {
        glDisable GL_MULTISAMPLE_ARB
    }
}

# 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 a Togl window using multisample buffers.
    # Reshape and Display callbacks are configured later after knowing if
    # the needed multisample buffers are available.
    set retVal [catch { togl .fr.toglwin \
        -width $::gDemo(winWidth) -height $::gDemo(winHeight) \
        -multisamplebuffers 1 -multisamplesamples 2 \
        -swapinterval 1 \
        -double true -depth true \
        -createcommand CreateCallback } errMsg]
    if { $retVal != 0 } {
        tk_messageBox -icon error -type ok -title "Missing Togl feature" \
                      -message "Demo needs multisample buffers: $errMsg"
        proc ::Cleanup {} {}
        exit 1
        return
    }

    .fr.toglwin configure \
        -reshapecommand ReshapeCallback \
        -displaycommand DisplayCallback

    listbox .fr.usage -font $::gDemo(listFont) -height 5
    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 & MainRoach's FSAA Tutorial (Lesson 46)"

    # Watch For ESC Key And Quit Messages
    wm protocol . WM_DELETE_WINDOW "ExitProg"
    bind . <Key-Escape> "ExitProg"
    bind . <Key-F1>     "ToggleWindowMode"
    bind . <Key-m>      "ToggleMultisampling .fr.toglwin"

    bind .fr.toglwin <1> "StartAnimation"
    bind .fr.toglwin <2> "StopAnimation"
    bind .fr.toglwin <3> "StopAnimation"
    bind .fr.toglwin <Control-Button-1> "StopAnimation"

    .fr.usage insert end "Key-Escape Exit"
    .fr.usage insert end "Key-F1     Toggle window mode"
    .fr.usage insert end "Key-m      Toggle multisampling"
    .fr.usage insert end "Mouse-L|MR Start|Stop animation"
    .fr.usage insert end " "

    .fr.usage configure -state disabled
}

CreateWindow
PrintFSAAInfo
PrintInfo [tcl3dOglGetInfoString]
if { [file tail [info script]] eq [file tail $::argv0] } {
    # If started directly from tclsh or wish, then start animation.
    update
    StartAnimation
}
