# OSG vector specific test procedures.
# These procedures are independent of the supplied vector class type.
#
# Cnstr-Vec     Vec constructors.        Vec as result.
# Vec-Scalar    Vec as input.            Scalar as result.
# VecScalar     Vec and scalar as input. No result.
# VecScalar-Vec Vec and scalar as input. Vec as result.
# Vec-Vec       Vec as input.            Vec as result.
# VecVec        Vec and Vec as input.    No result.
# VecVec-Scalar Vec and Vec as input.    Scalar as result.
# VecVec-Vec    Vec and Vec as input.    Vec as result.
# Vec-Vec       Vec as input.            Vector as result.
# VecNormalize  Vec as input.            Length before and after as result.
# VecCast       VecXd as input.          VecXf as result.

package require tcl3d

source testUtil.tcl

# The wrapped OSG vector classes in convenient testing bundles.
set vec2Classes [list osg::Vec2b osg::Vec2s osg::Vec2f osg::Vec2d]
set vec3Classes [list osg::Vec3b osg::Vec3s osg::Vec3f osg::Vec3d]
set vec4Classes [list osg::Vec4ub osg::Vec4b osg::Vec4s osg::Vec4f osg::Vec4d]
set vecAllClasses [list $vec2Classes $vec3Classes $vec4Classes]

set vecdClasses [list osg::Vec2d osg::Vec3d osg::Vec4d]

# Test procedure for the different types of vector constructors.
proc Cnstr-Vec { vecType size } {
    P "\nCnstr-Vec: $vecType Functionality: set Vector \[$vecType\]"

    set vec1 [$vecType]
    PN "Cnstr():" ; PV $vec1

    set vec2 [CreateVec1 $vecType $size]
    PN "Cnstr(1 2 3):" ; PV $vec2
}

# Test procedure for methods returning scalar information about a vector
# without the need to supply parameters.
proc Vec-Scalar { vecType vec } {
    P "\nVec-Scalar: $vecType Functionality: set Scalar \[\$In method\]"
    PN "In $vecType" ; PV $vec
    set size [$vec size]
    for { set i 0 } { $i < $size } { incr i } {
        set retVal [catch {eval $vec get $i} result]
        PN "Method get $i"
        if { $retVal == 0 } {
            P $result
        } else {
            P "Not supported"
        }
    }
    foreach m { x y z w r g b a valid isNaN size length length2 } {
        set retVal [catch {eval $vec $m} result]
        PN "Method $m"
        if { $retVal == 0 } {
            P $result
        } else {
            P "Not supported"
        }
    }

    foreach m { ptr } {
        set retVal [catch {eval $vec $m} result]
        PN "Method $m"
        if { $retVal == 0 } {
            P [GetPointerType $result]
        } else {
            P "Not supported"
        }
    }
}

# Test procedure for methods operating directly on a vector
# by supplying a scalar. 
proc VecScalar { vecType vec sc } {
    P "\nVecScalar: $vecType Functionality: \$In1 method \$In2"
    PN "In1 $vecType" ; PV $vec
    foreach m { addSelf subSelf mulSelf divSelf } {
        set localVec [$vec copy]
        set retVal [catch {eval $localVec $m $sc} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PV "$localVec"
        } else {
            P "Not supported"
        }
        $localVec -delete
    }
    return $result
}

# Test procedure for methods returning a vector generated
# by supplying a vector and a scalar.
proc VecScalar-Vec { vecType vec sc } {
    P "\nVecScalar-Vec: $vecType Functionality: set Vector \[\$In1 method \$In2\]"
    PN "In1 $vecType" ; PV $vec
    PN "In2"          ; P $sc
    foreach m { mul div } {
        set retVal [catch {eval $vec $m $sc} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PV $result
        } else {
            P "Not supported"
        }
    }
    return $result
}

# Test procedure for methods returning a vector generated
# by supplying a vector.
proc Vec-Vec { vecType vec } {
    P "\nVec-Vec: $vecType Functionality: set Vector \[\$In method\]"
    PN "In $vecType" ; PV $vec
    foreach m { negate copy } {
        set retVal [catch {eval $vec $m} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PV "$result"
        } else {
            P "Not supported"
        }
    }
    return $result
}

# Test procedure for methods operating directly on a vector
# by supplying another vector. 
proc VecVec { vecType vec1 vec2 } {
    P "\nVecVec: $vecType Functionality: \$In1 method \$In2"
    PN "In1 $vecType" ; PV $vec1
    PN "In2 $vecType" ; PV $vec2
    foreach m { addSelf subSelf mulSelf divSelf } {
        set localVec [$vec1 copy]
        set retVal [catch {eval $localVec $m $vec2} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PV "$localVec"
        } else {
            P "Not supported"
        }
        $localVec -delete
    }
    return $result
}

# Test procedure for methods returning a scalar generated
# by supplying two vectors.
proc VecVec-Scalar { vecType vec1 vec2 } {
    P "\nVecVec-Scalar: $vecType Functionality: set Scalar \[\$In1 method \$In2\]"
    PN "In1 $vecType" ; PV $vec1
    PN "In2 $vecType" ; PV $vec2
    foreach m { dot eq ne less } {
        set retVal [catch {eval $vec1 $m $vec2} result]
        PN "Method $m"
        if { $retVal == 0 } {
            P $result
        } else {
            P "Not supported"
        }
    }
    return $result
}

# Test procedure for methods returning a vector generated
# by supplying two vectors.
proc VecVec-Vec { vecType vec1 vec2 } {
    P "\nVecVec-Vec: $vecType Functionality: set Vector \[\$In1 method \$In2\]"
    PN "In1 $vecType" ; PV $vec1
    PN "In2 $vecType" ; PV $vec2
    foreach m { add sub cross } {
        set retVal [catch {eval $vec1 $m $vec2} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PV $result
        } else {
            P "Not supported"
        }
    }
    return $result
}

# Test procedure for normalize method. 
proc VecNormalize { vecType vec } {
    P "\nVecNormalize: $vecType Functionality: \$In normalize"
    set localVec [$vec copy]
    PN "In $vecType" ; PV $localVec
    set retVal [catch {$localVec normalize} result]
    PN "Method normalize"
    if { $retVal == 0 } {
        PV "$localVec"
        PN "Length before/after:" 
        P [format "%.3f %.3f" $result [$localVec length]]
    } else {
        P "Not supported"
    }
    return $result
}

# Test procedure for methods returning a vector casted from
# a supplied vector.
proc VecCast { vecType vec } {
    P "\nVecCast: $vecType Functionality: set Vector \[\$In cast\]"
    PN "In $vecType" ; PV $vec
    foreach m { asVec2f asVec3f asVec4f } {
        set retVal [catch {eval $vec $m} result]
        PN "Method $m"
        if { $retVal == 0 } {
            PN "[GetPointerType [$result ptr]]" 
            PV "$result"
        } else {
            P "Not supported"
        }
    }
    return $result
}

# Start of test cases.

P "\n>>> Test cases for osg::Vec classes <<<\n"

P "osg::Vec printed with tcl3dVectorPrint"
P "Vec2f:" ; tcl3dVectorPrint [CreateVec1 osg::Vec2f 2] 2
P "Vec3f:" ; tcl3dVectorPrint [CreateVec1 osg::Vec3f 3] 3
P "Vec4f:" ; tcl3dVectorPrint [CreateVec1 osg::Vec4f 4] 4

foreach vecSizeClasses $vecAllClasses size {2 3 4} {
    foreach vecType $vecSizeClasses {
        set ux [CreateUnitVec $vecType $size 0]
        set uy [CreateUnitVec $vecType $size 1]
        set v  [CreateVec2 $vecType $size]
        Cnstr-Vec      $vecType $size
        Vec-Scalar     $vecType $v
        VecScalar      $vecType $v 2.5
        VecScalar-Vec  $vecType $v 2.5
        Vec-Vec        $vecType $v
        VecVec         $vecType $ux $uy
        VecVec-Scalar  $vecType $ux $uy
        VecVec-Vec     $vecType $ux $uy
        VecNormalize   $vecType $v
        $ux -delete
        $uy -delete
        $v  -delete
    }
}

foreach vecType $vecdClasses size {2 3 4} {
    set v [CreateVec2 $vecType $size]
    VecCast $vecType $v
    $v -delete
}

exit
