#******************************************************************************
#
#       Copyright:      2009-2022 Paul Obermeier (obermeier@tcl3d.org)
#
#                       See the file "Tcl3D_License.txt" for information on
#                       usage and redistribution of this file, and for a
#                       DISCLAIMER OF ALL WARRANTIES.
#
#       Module:         Tcl3D -> tcl3dOgl
#       Filename:       tcl3dOglHelp.tcl
#
#       Author:         Paul Obermeier
#
#       Description:    Tcl module with help and information procedures
#                       related to the OpenGL module.
#
#******************************************************************************

###############################################################################
#[@e
#       Name:           tcl3dOglGetFuncList - Get list of OpenGL and GLU 
#                       functions.
#
#       Synopsis:       tcl3dOglGetFuncList { what }
#
#                       what : string (Default "gl")
#                       Allowed values for what ar: "gl", "glu" or "all"
#
#       Description:    Return a list of all wrapped OpenGL and/or GLU 
#                       function names.
#
#       See also:       tcl3dOglGetVersionList
#                       tcl3dOglIsFuncWrapped
#                       tcl3dOglGetVersionFuncs
#                       tcl3dOglGetVersionEnums
#
###############################################################################

proc tcl3dOglGetFuncList { { what "gl" } } {
    global __tcl3dOglFuncList __tcl3dGluFuncList

    if { $what eq "gl" } {
        return $__tcl3dOglFuncList
    }
    if { $what eq "glu" } {
        return $__tcl3dGluFuncList
    }
    return [concat $__tcl3dOglFuncList $__tcl3dGluFuncList]
}

# OBSOLETE tcl3dOglGetFuncSignatureList 0.4.2 None
proc tcl3dOglGetFuncSignatureList {} {
    global __tcl3dOglFuncSignatureList

    return $__tcl3dOglFuncSignatureList
}

# OBSOLETE tcl3dOglGetFuncVersionList 0.4.2 None
proc tcl3dOglGetFuncVersionList {} {
    global __tcl3dOglFuncVersionList

    return $__tcl3dOglFuncVersionList
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetVersionList - Get list of OpenGL versions 
#                       and extensions.
#
#       Synopsis:       tcl3dOglGetVersionList {}
#
#       Description:    Return a list of all wrapped OpenGL versions and
#                       extension names.
#                       The names are strings identical to their corresponding
#                       C defines.
#                       Examples:
#                       GL versions  : GL_VERSION_1_5, GL_VERSION_3_2
#                       GL extensions: GL_ARB_vertex_program, GL_EXT_texture3D
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetVersionFuncs
#                       tcl3dOglGetVersionEnums
#
###############################################################################

proc tcl3dOglGetVersionList {} {
    global __tcl3dOglFuncVersionList __tcl3dOglEnumVersion

    set tmp $__tcl3dOglFuncVersionList

    foreach {enum ext} [array get __tcl3dOglEnumVersion "*"] {
        lappend tmp $ext
    }
    return [lsort -unique $tmp]
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetExtensionList - Get list of OpenGL extensions.
#
#       Synopsis:       tcl3dOglGetExtensionList { {what "all"} }
#
#       Description:    Return a list of OpenGL extension names.
#                       The names are strings identical to their corresponding
#                       C defines.
#                       Examples:GL_ARB_vertex_program, GL_EXT_texture3D
#
#                       If "what" is equal to "all", all OpenGL extension names
#                       are returned.
#                       If "what" is equal to "glew", only the OpenGL
#                       extension names wrapped by GLEW are returned.
#                       If "what" is equal to "driver", only the OpenGL
#                       extension names supported by the driver and hardware of
#                       the actual machine are returned.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetVersionList
#                       tcl3dOglGetVersionFuncs
#                       tcl3dOglGetVersionEnums
#
###############################################################################

proc tcl3dOglGetExtensionList { {what "all"} } {
    global __tcl3dOglExtensionList

    if { $what eq "driver" } {
        return [lindex [tcl3dOglGetExtensions] 0 1]
    } elseif { $what eq "glew" } {
        return [tcl3dOglGetVersionList]
    } else {
        return [lsort [array names __tcl3dOglExtensionList]]
    }
}

###############################################################################
#[@e
#       Name:           tcl3dOglIsFuncWrapped - Check if OpenGL or GLU function
#                       is wrapped.
#
#       Synopsis:       tcl3dOglIsFuncWrapped { func }
#
#       Description:    Return true, if OpenGL or GLU function "func" is wrapped
#                       in Tcl3D. Otherwise return false.
#
#                       Note: To check, if a function is supported by the used
#                             OpenGL driver, use procedure "tcl3dOglHaveFunc".
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncSignature
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetFuncDeprecated
#                       tcl3dOglGetUrl
#
###############################################################################

proc tcl3dOglIsFuncWrapped { func } {
    global __tcl3dOglFuncList __tcl3dGluFuncList

    set ind [lsearch -exact $__tcl3dOglFuncList $func]
    if { $ind >= 0 } {
        return true
    } else {
        set ind [lsearch -exact $__tcl3dGluFuncList $func]
        if { $ind >= 0 } {
            return true
        }
    }
    return false
}

proc __tcl3dMapReturnValue { cval } {
    set cval [string map {"*" " *"} $cval]
    switch -glob -- $cval {
        {void}                { return "" }
        {GLboolean}           { return "bool" }
        {GLenum}              { return "enum" }
        {GL*int}              { return "int" }
        {const GLubyte[ ]*\*} { return "string" }
        {GLhandleARB}         -
        {GLsync}              -
        {GLintptr}            -
        {void[ ]*\*}          -
        {GLvoid[ ]*\*}        -
        {GLU*\*}              { return "SwigPointer" }
        default               { return "NOT_SUPPORTED" }
    }
}

proc __tcl3dMapParam { cval } {
    set cval [string map {"*" " * "} $cval]
    set paramName [string range $cval [string wordstart $cval end] end]
    switch -glob -- $cval {
        {const void[ ]*\**}   -
        {const GLvoid[ ]*\**} - 
        {void[ ]*\**}         -
        {GLvoid[ ]*\**}       { return "\[tcl3dVector TYPE\] $paramName" }
        {const *[ ]*\[*\]*}   -
        {const *[ ]*\**}      { set type [string range $cval [string wordstart $cval 8] \
                                                             [string wordend $cval 8]]
                                set type [string trim $type]
                                return "\[list of $type\] $paramName"
                              }
        {*[ ]*\**}            { set type [string range $cval 0 [string wordend $cval 0]]
                                set type [string trim $type]
                                return "\[tcl3dVector $type\] $paramName"
                              }
        {GLintptr*}           { return "\[tcl3dVector GLint\] $paramName" }
        {GLsizeiptr*}         { return "\[tcl3dVector GLsizei\] $paramName" }
        {GLenum*}             { return "enum $paramName" }
        {GLboolean*}          { return "bool $paramName" }
        {GLbitfield*}         { return "bitfield $paramName" }
        {GL*byte*}            -
        {GL*short*}           -
        {const GLint*}        -
        {GL*int*}             -
        {GLsizei*}            { return "int $paramName" }
        {GLhalf*}             -
        {GLclamp?*}           -
        {const GLfloat*}      -
        {GLfloat*}            -
        {GLdouble*}           { return "double $paramName" }
        {GLhandleARB*}        -
        {GLsync*}             { return "SwigPointer $paramName" }
        {void}                { return "" }
        default               { return "NOT_SUPPORTED" }
    }
}

proc tcl3dOglGetTclSignature { cSig } {
    set funcStart  [string first "gl" $cSig]
    set paramStart [string first "("  $cSig]
    set paramEnd   [string last  ")"  $cSig]
    set cRet   [string trim [string range $cSig 0 [expr {$funcStart-1}]]]
    set cFunc  [string trim [string range $cSig $funcStart [expr {$paramStart-1}]]]
    set tclRet [__tcl3dMapReturnValue $cRet]
    set tclSig ""
    if { $tclRet ne "" } {
        append tclSig "$tclRet "
    }
    append tclSig "$cFunc " 
    set cParams [string range $cSig [expr {$paramStart +1}] [expr {$paramEnd -1}]]
    foreach param [split $cParams ","] {
        set param [__tcl3dMapParam [string trim $param]]
        append tclSig "{$param} "
    }
    return $tclSig
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetFuncSignature - Get the signature of an 
#                       OpenGL or GLU function.
#
#       Synopsis:       tcl3dOglGetFuncSignature { func {what "c"} }
#
#       Description:    Return the signature of OpenGL or GLU function "func"
#                       as a string.
#                       If "func" is not contained in the list of wrapped 
#                       OpenGL functions (see tcl3dOglGetFuncList), an empty
#                       string is returned.
#
#                       If "what" is equal to "c", the signature string is returned
#                       in C style notation. This is the default case.
#                       If "what" is equal to "tcl", the signature string is returned
#                       in Tcl style notation.
#
#                       Note: This procedure replaces the obsolete
#                             tcl3dOglGetFuncSignatureList procedure.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetFuncDeprecated
#                       tcl3dOglGetUrl
#
###############################################################################

proc tcl3dOglGetFuncSignature { func { what "c" } } {
    global __tcl3dOglFuncList __tcl3dOglFuncSignatureList
    global __tcl3dGluFuncList __tcl3dGluFuncSignatureList

    set sigStr ""
    set ind [lsearch -exact $__tcl3dOglFuncList $func]
    if { $ind >= 0 } {
        set sigStr [lindex $__tcl3dOglFuncSignatureList $ind]
    } else {
        set ind [lsearch -exact $__tcl3dGluFuncList $func]
        if { $ind >= 0 } {
            set sigStr [lindex $__tcl3dGluFuncSignatureList $ind]
        }
    }
    if { $what eq "c" } {
        return $sigStr
    } else {
        return [tcl3dOglGetTclSignature $sigStr]
    }
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetFuncVersion - Get the version or extension
#                       name of an OpenGL function.
#
#       Synopsis:       tcl3dOglGetFuncVersion { func }
#
#       Description:    Return the version or extension name of OpenGL function
#                       "func" as a string.
#                       If "func" is not contained in the list of wrapped 
#                       OpenGL functions (see tcl3dOglGetFuncList), an empty
#                       string is returned.
#
#                       Note: This procedure replaces the obsolete
#                             tcl3dOglGetFuncVersionList procedure.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncSignature
#                       tcl3dOglGetFuncDeprecated
#                       tcl3dOglGetUrl
#                       tcl3dOglGetEnumVersion
#
###############################################################################

proc tcl3dOglGetFuncVersion { func } {
    global __tcl3dOglFuncList __tcl3dOglFuncVersionList

    set ind [lsearch -exact $__tcl3dOglFuncList $func]
    if { $ind >= 0 } {
        return [lindex $__tcl3dOglFuncVersionList $ind]
    } else {
        return ""
    }
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetEnumVersion - Get the version or extension
#                       name of an OpenGL enumeration.
#
#       Synopsis:       tcl3dOglGetEnumVersion { enum }
#
#       Description:    Return the version or extension name of OpenGL
#                       enumeration "enum" as a string.
#                       If "enum" is not a wrapped OpenGL enumeration,
#                       an empty string is returned.
#
#       See also:       tcl3dOglGetVersionList
#                       tcl3dOglGetVersionFuncs
#                       tcl3dOglGetVersionEnums
#                       tcl3dOglGetFuncVersion
#
###############################################################################

proc tcl3dOglGetEnumVersion { enum } {
    global __tcl3dOglEnumVersion

    if { [info exists __tcl3dOglEnumVersion($enum)] } {
        return $__tcl3dOglEnumVersion($enum)
    } else {
        return ""
    }
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetFuncDeprecated - Get the OpenGL version, an
#                       OpenGL function has been declared deprecated.
#
#       Synopsis:       tcl3dOglGetFuncDeprecated { func }
#
#       Description:    Return the version when OpenGL function "func" has been
#                       declared deprecated.
#                       The result is in the format "3.1", "3.2".
#                       For non-deprecated functions "0.0" is returned.
#
#                       If "func" is not contained in the list of wrapped 
#                       OpenGL functions (see tcl3dOglGetFuncList), an empty
#                       string is returned.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetFuncSignature
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetUrl
#
###############################################################################

proc tcl3dOglGetFuncDeprecated { func } {
    global __tcl3dOglFuncList __tcl3dOglFuncDeprecatedList

    set ind [lsearch -exact $__tcl3dOglFuncList $func]
    if { $ind >= 0 } {
        return [lindex $__tcl3dOglFuncDeprecatedList $ind]
    } else {
        return ""
    }
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetUrl - Get the URL of the official
#                       documentation of an OpenGL item.
#
#       Synopsis:       tcl3dOglGetUrl { item }
#
#       Description:    Return the URL of the official documentation of OpenGL
#                       item "item" as a string.
#                       Item can be the name of a function, extension or 
#                       enumeration. 
#                       If no documentation page exists, a Google search URL
#                       for that item is returned.
#
#                       Note: The documentation pages on www.opengl.org
#                             currently only include OpenGL up to version 2.1.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetVersionFuncs
#                       tcl3dOglGetVersionEnums
#
###############################################################################

proc tcl3dOglGetUrl { item } {
    global __tcl3dOglFuncList __tcl3dOglFuncUrlList
    global __tcl3dGluFuncList __tcl3dGluFuncUrlList
    global __tcl3dOglFuncVersionList __tcl3dOglEnumVersion
    global __tcl3dOglExtensionList

    # First check, if item is an OpenGL command.
    set ind [lsearch -exact $__tcl3dOglFuncList $item]
    if { $ind >= 0 } {
        return [lindex $__tcl3dOglFuncUrlList $ind]
    }
    # Then check, if item is an OpenGL GLU command.
    set ind [lsearch -exact $__tcl3dGluFuncList $item]
    if { $ind >= 0 } {
        return [lindex $__tcl3dGluFuncUrlList $ind]
    }
    # Then check, if item is an OpenGL extension name.
    if { [info exists __tcl3dOglExtensionList($item)] } {
        return $__tcl3dOglExtensionList($item)
    }
    # Then check, if item is an OpenGL enumeration name.
    foreach {enum ext} [array get ::__tcl3dOglEnumVersion "*"] {
        if { $enum eq $item } {
            if { ! [string match "GL_VERSION_*" $ext] } {
                # It is an enumeration specified in an OpenGL extension.
                # Link to the corresponding extension page.
                if { [info exists __tcl3dOglExtensionList($ext)] } {
                    return $__tcl3dOglExtensionList($ext)
                }
                set ind [lsearch -exact $__tcl3dOglFuncVersionList $ext]
                if { $ind >= 0 } {
                    return [lindex $__tcl3dOglFuncUrlList $ind]
                }
            }
        }
    }

    # We have not found a detailled link. Issue a Google search.
    return "http://www.google.com/search?q=$item"
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetVersionFuncs - Get the function names of an
#                       OpenGL version or extension.
#
#       Synopsis:       tcl3dOglGetVersionFuncs { version }
#
#       Description:    Return the function names of OpenGL version or extension
#                       "version" as a list.
#                       If "version" is not a supported version or extension,
#                       an empty list is returned.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetVersionList
#                       tcl3dOglGetFuncVersion
#                       tcl3dOglGetVersionEnums
#
###############################################################################

proc tcl3dOglGetVersionFuncs { version } {
    global __tcl3dOglFuncList __tcl3dOglFuncVersionList

    set funcList [list]
    set indList [lsearch -exact -all $__tcl3dOglFuncVersionList $version]
    foreach ind $indList {
        lappend funcList [lindex $__tcl3dOglFuncList $ind]
    }
    return $funcList
}

###############################################################################
#[@e
#       Name:           tcl3dOglGetVersionEnums - Get the enumeration names of
#                       an OpenGL version or extension.
#
#       Synopsis:       tcl3dOglGetVersionEnums { version }
#
#       Description:    Return the enumeration names of OpenGL version or
#                       extension "version" as a list.
#                       If "version" is not a supported version or extension,
#                       an empty list is returned.
#
#       See also:       tcl3dOglGetFuncList
#                       tcl3dOglGetVersionList
#                       tcl3dOglGetEnumVersion
#                       tcl3dOglGetVersionFuncs
#
###############################################################################

proc tcl3dOglGetVersionEnums { version } {
    global __tcl3dOglEnumVersion

    set enumList [list]
    foreach {enum ext} [array get __tcl3dOglEnumVersion "*"] {
        if { $ext eq $version } {
            lappend enumList $enum
        }
    }
    return $enumList
}
