// <ZZ> This file contains functions for detecting geometric collisions...
unsigned char global_collision_backface;

//-----------------------------------------------------------------------------------------------
float collide_sphere_triangle(float* sphere_xyz, float radius, float* a_xyz, float* b_xyz, float* c_xyz, float* triangle_normal_xyz)
{
    // <ZZ> This function determines whether a given sphere and a given triangle intersect.
    //      If they do not intersect, it returns a negative number.  If they do intersect,
    //      the function returns a positive number that indicates how far into the triangle
    //      the sphere is pressing.  sphere_xyz gives us the center of the sphere, and radius
    //      tells us the radius.  a_xyz, b_xyz, and c_xyz tell us the three points of the
    //      triangle.  triangle_normal_xyz tells us the normal vector of the plane of the
    //      triangle (which we computed earlier).
    float dis_xyz[3], side_xyz[3], side_normal_xyz[3];
    float dis;
    float side_dis;
    float radius_squared;



    // Find the shortest distance from the center of the sphere to the plane of the triangle...
    dis_xyz[X] = sphere_xyz[X] - a_xyz[X];
    dis_xyz[Y] = sphere_xyz[Y] - a_xyz[Y];
    dis_xyz[Z] = sphere_xyz[Z] - a_xyz[Z];
    dis = dot_product(dis_xyz, triangle_normal_xyz);



    // Is the sphere close enough to the plane of the triangle to warrant further checking?
//    if(dis < radius && dis > -radius)
global_collision_backface = (dis < 0.0f);
dis = (dis > 0.0f) ? dis : -dis;
if(dis < radius)
//    if(dis < radius && dis > 0.0f)
    {
        // Yes, the sphere is close to the plane of the triangle...  Let's first check for
        // a direct hit on the triangle (meaning the center of the sphere is within the
        // volume defined by extruding the triangle along its normal)


        // First side extrusion...
        side_xyz[X] = a_xyz[X] - b_xyz[X];
        side_xyz[Y] = a_xyz[Y] - b_xyz[Y];
        side_xyz[Z] = a_xyz[Z] - b_xyz[Z];
        cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
        side_dis = dot_product(dis_xyz, side_normal_xyz);
        if(side_dis < 0.0)
        {
            // Second side extrusion...  Dis must be the distance from sphere center
            // to a point on the line/plane -- so we'll need to switch that up...
            dis_xyz[X] = sphere_xyz[X] - c_xyz[X];
            dis_xyz[Y] = sphere_xyz[Y] - c_xyz[Y];
            dis_xyz[Z] = sphere_xyz[Z] - c_xyz[Z];
            side_xyz[X] = b_xyz[X] - c_xyz[X];
            side_xyz[Y] = b_xyz[Y] - c_xyz[Y];
            side_xyz[Z] = b_xyz[Z] - c_xyz[Z];
            cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
            side_dis = dot_product(dis_xyz, side_normal_xyz);
            if(side_dis < 0.0f)
            {
                // Third side extrusion...
                side_xyz[X] = c_xyz[X] - a_xyz[X];
                side_xyz[Y] = c_xyz[Y] - a_xyz[Y];
                side_xyz[Z] = c_xyz[Z] - a_xyz[Z];
                cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
                side_dis = dot_product(dis_xyz, side_normal_xyz);
                if(side_dis < 0.0f)
                {
                    // We have a direct collision, so return the distance into the triangle the sphere is pressing...
                    return (radius-dis);
                }
            }
        }


        // We don't have a direct collision, but we might have a collision with one of
        // the edges of the triangle...  We'll need our radius squared to help determine
        // that...
        radius_squared = radius*radius;



        // Find the closest point on the first edge to the sphere...
        dis_xyz[X] = sphere_xyz[X] - a_xyz[X];
        dis_xyz[Y] = sphere_xyz[Y] - a_xyz[Y];
        dis_xyz[Z] = sphere_xyz[Z] - a_xyz[Z];
        side_xyz[X] = b_xyz[X] - a_xyz[X];
        side_xyz[Y] = b_xyz[Y] - a_xyz[Y];
        side_xyz[Z] = b_xyz[Z] - a_xyz[Z];
        dis = dot_product(dis_xyz, side_xyz);
        side_dis = dot_product(side_xyz, side_xyz);
        // Make sure the line segment isn't of 0 length...
        if(side_dis > 0.0f)
        {
            // Limit range between 0.0 and 1.0 (so it's on our line segment)
            dis = dis/side_dis;
            dis = (dis < 0.0f) ? 0.0f : dis;
            dis = (dis > 1.0f) ? 1.0f : dis;


            // Determine the distance to the sphere from the closest point on the line segment...
//dis_xyz[X] = (a_xyz[X] + dis*side_xyz[X]);
//dis_xyz[Y] = (a_xyz[Y] + dis*side_xyz[Y]);
//dis_xyz[Z] = (a_xyz[Z] + dis*side_xyz[Z]);
//particle_draw(dis_xyz, 1.0f, sphere_texture);
            dis_xyz[X] = sphere_xyz[X] - (a_xyz[X] + dis*side_xyz[X]);
            dis_xyz[Y] = sphere_xyz[Y] - (a_xyz[Y] + dis*side_xyz[Y]);
            dis_xyz[Z] = sphere_xyz[Z] - (a_xyz[Z] + dis*side_xyz[Z]);
            dis = dis_xyz[X]*dis_xyz[X] + dis_xyz[Y]*dis_xyz[Y] + dis_xyz[Z]*dis_xyz[Z];
            if(dis < radius_squared)
            {
                // We have a collision on this line segment...
                dis = (float) sqrt(dis);
                return (radius-dis);
            }
        }




        // Find the closest point on the second edge to the sphere...
        dis_xyz[X] = sphere_xyz[X] - b_xyz[X];
        dis_xyz[Y] = sphere_xyz[Y] - b_xyz[Y];
        dis_xyz[Z] = sphere_xyz[Z] - b_xyz[Z];
        side_xyz[X] = c_xyz[X] - b_xyz[X];
        side_xyz[Y] = c_xyz[Y] - b_xyz[Y];
        side_xyz[Z] = c_xyz[Z] - b_xyz[Z];
        dis = dot_product(dis_xyz, side_xyz);
        side_dis = dot_product(side_xyz, side_xyz);
        // Make sure the line segment isn't of 0 length...
        if(side_dis > 0.0f)
        {
            // Limit range between 0.0 and 1.0 (so it's on our line segment)
            dis = dis/side_dis;
            dis = (dis < 0.0f) ? 0.0f : dis;
            dis = (dis > 1.0f) ? 1.0f : dis;


            // Determine the distance to the sphere from the closest point on the line segment...
//dis_xyz[X] = (b_xyz[X] + dis*side_xyz[X]);
//dis_xyz[Y] = (b_xyz[Y] + dis*side_xyz[Y]);
//dis_xyz[Z] = (b_xyz[Z] + dis*side_xyz[Z]);
//particle_draw(dis_xyz, 1.0f, sphere_texture);
            dis_xyz[X] = sphere_xyz[X] - (b_xyz[X] + dis*side_xyz[X]);
            dis_xyz[Y] = sphere_xyz[Y] - (b_xyz[Y] + dis*side_xyz[Y]);
            dis_xyz[Z] = sphere_xyz[Z] - (b_xyz[Z] + dis*side_xyz[Z]);
            dis = dis_xyz[X]*dis_xyz[X] + dis_xyz[Y]*dis_xyz[Y] + dis_xyz[Z]*dis_xyz[Z];
            if(dis < radius_squared)
            {
                // We have a collision on this line segment...
                dis = (float) sqrt(dis);
                return (radius-dis);
            }
        }



        // Find the closest point on the third edge to the sphere...
        dis_xyz[X] = sphere_xyz[X] - c_xyz[X];
        dis_xyz[Y] = sphere_xyz[Y] - c_xyz[Y];
        dis_xyz[Z] = sphere_xyz[Z] - c_xyz[Z];
        side_xyz[X] = a_xyz[X] - c_xyz[X];
        side_xyz[Y] = a_xyz[Y] - c_xyz[Y];
        side_xyz[Z] = a_xyz[Z] - c_xyz[Z];
        dis = dot_product(dis_xyz, side_xyz);
        side_dis = dot_product(side_xyz, side_xyz);
        // Make sure the line segment isn't of 0 length...
        if(side_dis > 0.0f)
        {
            // Limit range between 0.0 and 1.0 (so it's on our line segment)
            dis = dis/side_dis;
            dis = (dis < 0.0f) ? 0.0f : dis;
            dis = (dis > 1.0f) ? 1.0f : dis;


            // Determine the distance to the sphere from the closest point on the line segment...
//dis_xyz[X] = (c_xyz[X] + dis*side_xyz[X]);
//dis_xyz[Y] = (c_xyz[Y] + dis*side_xyz[Y]);
//dis_xyz[Z] = (c_xyz[Z] + dis*side_xyz[Z]);
//particle_draw(dis_xyz, 1.0f, sphere_texture);
            dis_xyz[X] = sphere_xyz[X] - (c_xyz[X] + dis*side_xyz[X]);
            dis_xyz[Y] = sphere_xyz[Y] - (c_xyz[Y] + dis*side_xyz[Y]);
            dis_xyz[Z] = sphere_xyz[Z] - (c_xyz[Z] + dis*side_xyz[Z]);
            dis = dis_xyz[X]*dis_xyz[X] + dis_xyz[Y]*dis_xyz[Y] + dis_xyz[Z]*dis_xyz[Z];
            if(dis < radius_squared)
            {
                // We have a collision on this line segment...
                dis = (float) sqrt(dis);
                return (radius-dis);
            }
        }
    }
    return -1.0f;
}

//-----------------------------------------------------------------------------------------------
float collide_line_triangle(float* l_xyz, float* m_xyz, float* a_xyz, float* b_xyz, float* c_xyz, float* triangle_normal_xyz)
{
    // <ZZ> This function determines whether a given line segment intersects a given
    //      triangle.  If they do not intersect, it returns a negative number.  If they do
    //      intersect, the function returns a positive number that indicates how far into the
    //      triangle the line is pressing.  l_xyz and m_xyz give the end points of the
    //      line segment.  a_xyz, b_xyz, and c_xyz tell us the three points of the
    //      triangle.  triangle_normal_xyz tells us the normal vector of the plane of the
    //      triangle (which we computed earlier).
    float lm_xyz[3], al_xyz[3], am_xyz[3], i_xyz[3], dis_xyz[3], side_xyz[3], side_normal_xyz[3];
    float dis, dot_lm, dot_al, dot_am;
    float side_dis;


    // We have a possible intersection only if one point is in front of the triangle
    // (in direction of normal) and one point is behind the triangle...
    al_xyz[X] = l_xyz[X] - a_xyz[X];
    al_xyz[Y] = l_xyz[Y] - a_xyz[Y];
    al_xyz[Z] = l_xyz[Z] - a_xyz[Z];
    dot_al = dot_product(al_xyz, triangle_normal_xyz);

    am_xyz[X] = m_xyz[X] - a_xyz[X];
    am_xyz[Y] = m_xyz[Y] - a_xyz[Y];
    am_xyz[Z] = m_xyz[Z] - a_xyz[Z];
    dot_am = dot_product(am_xyz, triangle_normal_xyz);


    // Are the signs of the dot products opposite?
    if((dot_al > 0.0f && dot_am < 0.0f) || (dot_al < 0.0f && dot_am > 0.0f))
    {
        // Line intersects the plane of the triangle, but does it intersect the triangle?
        lm_xyz[X] = m_xyz[X] - l_xyz[X];
        lm_xyz[Y] = m_xyz[Y] - l_xyz[Y];
        lm_xyz[Z] = m_xyz[Z] - l_xyz[Z];
        dis = -dot_al;
        dot_lm = dot_product(lm_xyz, triangle_normal_xyz);
        dis = dis / dot_lm;
        if(dis > 0.0f && dis < 1.0f)
        {
            // Find the position of the intersection point....
            i_xyz[X] = lm_xyz[X]*dis + l_xyz[X];
            i_xyz[Y] = lm_xyz[Y]*dis + l_xyz[Y];
            i_xyz[Z] = lm_xyz[Z]*dis + l_xyz[Z];


            // Is this intersection point within our triangle?
            // This can be determined by extruding each side of the triangle according to
            // its normal vector...


            // First side extrusion...
            dis_xyz[X] = i_xyz[X] - b_xyz[X];
            dis_xyz[Y] = i_xyz[Y] - b_xyz[Y];
            dis_xyz[Z] = i_xyz[Z] - b_xyz[Z];
            side_xyz[X] = a_xyz[X] - b_xyz[X];
            side_xyz[Y] = a_xyz[Y] - b_xyz[Y];
            side_xyz[Z] = a_xyz[Z] - b_xyz[Z];
            cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
            side_dis = dot_product(dis_xyz, side_normal_xyz);
            if(side_dis < 0.0)
            {
                // Second side extrusion...
                side_xyz[X] = b_xyz[X] - c_xyz[X];
                side_xyz[Y] = b_xyz[Y] - c_xyz[Y];
                side_xyz[Z] = b_xyz[Z] - c_xyz[Z];
                cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
                side_dis = dot_product(dis_xyz, side_normal_xyz);
                if(side_dis < 0.0f)
                {
                    // Third side extrusion...
                    dis_xyz[X] = i_xyz[X] - a_xyz[X];
                    dis_xyz[Y] = i_xyz[Y] - a_xyz[Y];
                    dis_xyz[Z] = i_xyz[Z] - a_xyz[Z];
                    side_xyz[X] = c_xyz[X] - a_xyz[X];
                    side_xyz[Y] = c_xyz[Y] - a_xyz[Y];
                    side_xyz[Z] = c_xyz[Z] - a_xyz[Z];
                    cross_product(triangle_normal_xyz, side_xyz, side_normal_xyz);
                    side_dis = dot_product(dis_xyz, side_normal_xyz);
                    if(side_dis < 0.0f)
                    {
                        // We have a direct collision, so return the distance into the triangle the line is pressing...
                        global_collision_xyz[X] = i_xyz[X];
                        global_collision_xyz[Y] = i_xyz[Y];
                        global_collision_xyz[Z] = i_xyz[Z];
                        if(dot_am < 0.0f)
                        {
                            // This is the standard case (where l specifies the start of a line segment
                            // and m is the end -- and m is pressing into the triangle which is facing l)
                            global_collision_backface = FALSE;
                            return -dot_am;
                        }
                        else
                        {
                            // This is the backface case...
                            global_collision_backface = TRUE;
                            return dot_am;
                        }
                    }
                }
            }
        }
    }
    return -1.0f;
}

//-----------------------------------------------------------------------------------------------
/*
#define MAX_DIVISION 500
float collide_cylinder_triangle(float* l_xyz, float* m_xyz, float radius, float* a_xyz, float* b_xyz, float* c_xyz, float* triangle_normal_xyz)
{
    // <ZZ> This function determines whether a given cylinder (with ball caps) intersects a given
    //      triangle.  If they do not intersect, it returns a negative number.  If they do
    //      intersect, the function returns a positive number that indicates how far into the
    //      triangle (roughly) the cylinder is pressing.  l_xyz and m_xyz give the end points
    //      of the cylinder.  a_xyz, b_xyz, and c_xyz tell us the three points of the
    //      triangle.  triangle_normal_xyz tells us the normal vector of the plane of the
    //      triangle (which we computed earlier).  radius is the radius of the cylinder.
    //      
    //      This function works by generating a bunch of point locations on the triangle
    //      surface, and finding the minimum distance from each point to the line segment
    //      that runs through the center of the cylinder.
    //
    //      We determine the number of points dynamically, since we know the radius of the
    //      cylinder -- this is akin to a fly not being able to fit through a screen
    //
    //      The coordinates of the test point which was found to exist within the ball-capped cylinder
    //      is made available as a global...
    int i, j, count;
    int num_divisions;
    float ab_xyz[3];
    float ac_xyz[3];
    float bc_xyz[3];
    float am_xyz[3];
    float lm_xyz[3];
    float lp_xyz[3];
    float n_xyz[3];
    float p_xyz[3];
    float pn_xyz[3];
    float dis_ab;
    float dis_ac;
    float dis_bc;
    float dis_lm;
    float dis;
    float best_dis;
    float dot;
    float ab_division_xyz[MAX_DIVISION][3];
    float ac_division_xyz[MAX_DIVISION][3];
    float adder, percent, inverse;
    unsigned char hit_detected;
    unsigned char endcap_hit;
    unsigned char best_endcap_hit;

    // By default, we have no collision detected...
    hit_detected = FALSE;
    best_endcap_hit = FALSE;


    // Find the edge vectors...
    ab_xyz[X] = b_xyz[X] - a_xyz[X];
    ab_xyz[Y] = b_xyz[Y] - a_xyz[Y];
    ab_xyz[Z] = b_xyz[Z] - a_xyz[Z];
    ac_xyz[X] = c_xyz[X] - a_xyz[X];
    ac_xyz[Y] = c_xyz[Y] - a_xyz[Y];
    ac_xyz[Z] = c_xyz[Z] - a_xyz[Z];
    bc_xyz[X] = c_xyz[X] - b_xyz[X];
    bc_xyz[Y] = c_xyz[Y] - b_xyz[Y];
    bc_xyz[Z] = c_xyz[Z] - b_xyz[Z];


    // Determine the length of each edge vector...
    dis_ab = ab_xyz[X]*ab_xyz[X] + ab_xyz[Y]*ab_xyz[Y] + ab_xyz[Z]*ab_xyz[Z];
    dis_ac = ac_xyz[X]*ac_xyz[X] + ac_xyz[Y]*ac_xyz[Y] + ac_xyz[Z]*ac_xyz[Z];
    dis_bc = bc_xyz[X]*bc_xyz[X] + bc_xyz[Y]*bc_xyz[Y] + bc_xyz[Z]*bc_xyz[Z];
    if(dis_ab > dis_ac && dis_ab > dis_bc)
    {
        dis = dis_ab;
    }
    else if(dis_ac > dis_bc)
    {
        dis = dis_ac;
    }
    else
    {
        dis = dis_bc;
    }
    dis = (float) sqrt(dis);


    // Determine the length of the cylinder...
    lm_xyz[X] = m_xyz[X] - l_xyz[X];
    lm_xyz[Y] = m_xyz[Y] - l_xyz[Y];
    lm_xyz[Z] = m_xyz[Z] - l_xyz[Z];
    dis_lm = lm_xyz[X]*lm_xyz[X] + lm_xyz[Y]*lm_xyz[Y] + lm_xyz[Z]*lm_xyz[Z];
    dis_lm = (float) sqrt(dis_lm);
    dis_lm += 0.000000000001f;


    // Determine how many divisions each edge of the triangle should be broken into,
    // based on its length versus the radius of the cylinder/caps
    num_divisions = ((int) (2.0f * dis / radius)) + 2;
    num_divisions = (num_divisions > MAX_DIVISION) ? MAX_DIVISION : num_divisions;


    // Determine the XYZ coordinates of several points along the ab and ac edges of
    // the triangle...
    adder = 1.0f / (num_divisions-1);
    percent = 0.0f;
    inverse = 1.0f;
    repeat(i, num_divisions)
    {
      ab_division_xyz[i][X] = a_xyz[X]*inverse + b_xyz[X]*percent;
      ab_division_xyz[i][Y] = a_xyz[Y]*inverse + b_xyz[Y]*percent;
      ab_division_xyz[i][Z] = a_xyz[Z]*inverse + b_xyz[Z]*percent;
      ac_division_xyz[i][X] = a_xyz[X]*inverse + c_xyz[X]*percent;
      ac_division_xyz[i][Y] = a_xyz[Y]*inverse + c_xyz[Y]*percent;
      ac_division_xyz[i][Z] = a_xyz[Z]*inverse + c_xyz[Z]*percent;
      percent += adder;
      inverse -= adder;
    }


    // We'll use radius squared later to make our check easier...
    best_dis = radius*radius;


    // Normalize the lm vector...
    lm_xyz[X]/=dis_lm;
    lm_xyz[Y]/=dis_lm;
    lm_xyz[Z]/=dis_lm;


    // Now, walk through the triangle in a grid-like manner, finding test
    // points, and the distance of each point to the cylinder...
    repeat(i, num_divisions)
    {
        // Determine how much of a step there is between points...
        count = i+1;
        adder = 1.0f;
        if(i > 0)
        {
           adder /= i;
        }
        percent = 0.0f;
        inverse = 1.0f;
        repeat(j, count)
        {
            // Find the test point location...
            p_xyz[X] = ab_division_xyz[i][X]*percent + ac_division_xyz[i][X]*inverse;
            p_xyz[Y] = ab_division_xyz[i][Y]*percent + ac_division_xyz[i][Y]*inverse;
            p_xyz[Z] = ab_division_xyz[i][Z]*percent + ac_division_xyz[i][Z]*inverse;



            // Find the nearest point on the lm line segment to the test point...
            lp_xyz[X] = p_xyz[X] - l_xyz[X];
            lp_xyz[Y] = p_xyz[Y] - l_xyz[Y];
            lp_xyz[Z] = p_xyz[Z] - l_xyz[Z];
            dot = dot_product(lm_xyz, lp_xyz);
            endcap_hit = (dot < 0.0f || dot > dis_lm) ? TRUE : FALSE;
            dot = (dot > 0.0f) ? dot : 0.0f;
            dot = (dot < dis_lm) ? dot : dis_lm;
            n_xyz[X] = l_xyz[X] + lm_xyz[X]*dot;
            n_xyz[Y] = l_xyz[Y] + lm_xyz[Y]*dot;
            n_xyz[Z] = l_xyz[Z] + lm_xyz[Z]*dot;


            // Determine the distance from the test point to the nearest point...
            pn_xyz[X] = n_xyz[X] - p_xyz[X];
            pn_xyz[Y] = n_xyz[Y] - p_xyz[Y];
            pn_xyz[Z] = n_xyz[Z] - p_xyz[Z];
            dis = pn_xyz[X]*pn_xyz[X] + pn_xyz[Y]*pn_xyz[Y] + pn_xyz[Z]*pn_xyz[Z];

if(debug_draw)
{
    if(dis < (radius*radius))
    {
        display_marker(red, p_xyz[X], p_xyz[Y], p_xyz[Z], 0.10f);
    }
    else
    {
        display_marker(green, p_xyz[X], p_xyz[Y], p_xyz[Z], 0.10f);
    }
}


            // Is this point within our radius...  The end caps are radius'd as well,
            // so it's a simple test...  dis and radius are both squared here, but it
            // doesn't matter...
            if(dis < best_dis)
            {
                best_dis = dis;
                hit_detected = TRUE;
                best_endcap_hit = endcap_hit;
                global_collision_xyz[X] = n_xyz[X];
                global_collision_xyz[Y] = n_xyz[Y];
                global_collision_xyz[Z] = n_xyz[Z];
                global_collision_percent = dot/dis_lm;
            }


            // Move to our next point...
            percent += adder;
            inverse -= adder;
        }
    }




    if(hit_detected)
    {
if(debug_draw)
{
    display_sphere(yellow, global_collision_xyz[X], global_collision_xyz[Y], global_collision_xyz[Z], 0.10f, 8, 8);
}



        // This cylinder has collided with the triangle, 
        // but is it a glancing hit, or one that passes all the
        // way through the triangle?
        dis = collide_line_triangle(l_xyz, m_xyz, a_xyz, b_xyz, c_xyz, triangle_normal_xyz);
        if(dis < 0.0f || best_endcap_hit)
        {
            // We had a glancing hit or an endcap collision...
            best_dis = (float) sqrt(best_dis);
            best_dis = radius-best_dis;
        }
        else
        {
            // We had a direct hit...
            best_dis = dis_lm - (global_collision_percent*dis_lm) + radius;
        }
//            best_dis = dis+global_scope_radius;
//        }
//        if(dis < 0.0f)
//        {
//            // We didn't have a direct hit, so let's determine if it's a backface hit or not...
//            am_xyz[X] = m_xyz[X] - a_xyz[X];
//            am_xyz[Y] = m_xyz[Y] - a_xyz[Y];
//            am_xyz[Z] = m_xyz[Z] - a_xyz[Z];
//            dot = dot_product(am_xyz, triangle_normal_xyz);
//            if(dot < 0.0)
//            {
//                global_collision_backface = FALSE;
//            }
//            else
//            {
//                global_collision_backface = TRUE;
//            }
//        }



        return best_dis;
    }
    return -1.0f;
}
*/
//------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------
/*
float collide_cylinder_triangle(float* l_xyz, float* m_xyz, float radius, float* a_xyz, float* b_xyz, float* c_xyz, float* triangle_normal_xyz)
{
    // <ZZ> This function determines whether a given cylinder intersects a given
    //      triangle.  If they do not intersect, it returns a negative number.  If they do
    //      intersect, the function returns a positive number that indicates how far into the
    //      triangle the line is pressing.  l_xyz and m_xyz give the end points of the
    //      cylinder.  a_xyz, b_xyz, and c_xyz tell us the three points of the
    //      triangle.  triangle_normal_xyz tells us the normal vector of the plane of the
    //      triangle (which we computed earlier).  radius is the radius of the cylinder.

    //      Top and bottom edge cases are not handled
    float la_xyz[3], lb_xyz[3], lc_xyz[3], side_normal_xyz[3];
    float fore_xyz[3], up_xyz[3], side_xyz[3];
    float dis, dot_lm, dot_al, dot_am;
    float side_dis;
    float newa_xyz[3];
    float newb_xyz[3];
    float newc_xyz[3];


    // Transform all 3 triangle points into the cylinder's coordinate system...
    fore_xyz[X] = m_xyz[X]-l_xyz[X];
    fore_xyz[Y] = m_xyz[Y]-l_xyz[Y];
    fore_xyz[Z] = m_xyz[Z]-l_xyz[Z];
    normalize(fore_xyz);
    la_xyz[X] = a_xyz[X] - l_xyz[X];
    la_xyz[Y] = a_xyz[Y] - l_xyz[Y];
    la_xyz[Z] = a_xyz[Z] - l_xyz[Z];
    lb_xyz[X] = b_xyz[X] - l_xyz[X];
    lb_xyz[Y] = b_xyz[Y] - l_xyz[Y];
    lb_xyz[Z] = b_xyz[Z] - l_xyz[Z];
    lc_xyz[X] = c_xyz[X] - l_xyz[X];
    lc_xyz[Y] = c_xyz[Y] - l_xyz[Y];
    lc_xyz[Z] = c_xyz[Z] - l_xyz[Z];
    newa_xyz[Z] = dot_product(la_xyz, fore_xyz);
    newb_xyz[Z] = dot_product(lb_xyz, fore_xyz);
    newc_xyz[Z] = dot_product(lc_xyz, fore_xyz);

    // Early exit test -- can't have a collision if all are > 0
    // or all are < -global_normal_length...
    if((newa_xyz[Z] > 0.0f && newb_xyz[Z] > 0.0f && newc_xyz[Z] > 0.0f) || (newa_xyz[Z] < -global_normal_length && newb_xyz[Z] < -global_normal_length && newc_xyz[Z] < -global_normal_length))
    {
        return -1.0f;
    }
    else
    {
        // We may possibly have a collision, so let's continue transforming these coordinates...
        side_xyz[X] = fore_xyz[X]+1.0f;
        side_xyz[Y] = fore_xyz[Y]-1.0f;
        side_xyz[Z] = fore_xyz[Z];
        cross_product(fore_xyz, side_xyz, up_xyz);
        cross_product(fore_xyz, up_xyz, side_xyz);
        normalize(side_xyz);
        normalize(up_xyz);

        newa_xyz[X] = dot_product(la_xyz, side_xyz);
        newb_xyz[X] = dot_product(lb_xyz, side_xyz);
        newc_xyz[X] = dot_product(lc_xyz, side_xyz);
        newa_xyz[Y] = dot_product(la_xyz, up_xyz);
        newb_xyz[Y] = dot_product(lb_xyz, up_xyz);
        newc_xyz[Y] = dot_product(lc_xyz, up_xyz);

        // We're now looking at the triangle top down (x and y)
        // with the cylinder centered at 0, 0...

        // Are any of the triangle's points within the cylinder itself?

        // 

// return xyz coordinates of collision
    }
    return -1.0f;
}
*/

//------------------------------------------------------------------------------------
float collide_point_line(float* p_xyz, float* l_xyz, float* m_xyz, float length)
{
    // <ZZ> This function determines the minimum distance (squared) between a point
    //      and a line segment.
    float lm_xyz[3];
    float lp_xyz[3];
    float n_xyz[3];
    float dot, dis;

    if(length > 0.0f)
    {
        // Find the normalized vector pointing along the line segment...
        lm_xyz[X] = m_xyz[X] - l_xyz[X];
        lm_xyz[Y] = m_xyz[Y] - l_xyz[Y];
        lm_xyz[Z] = m_xyz[Z] - l_xyz[Z];
        lm_xyz[X]/=length;
        lm_xyz[Y]/=length;
        lm_xyz[Z]/=length;

        // Find the point along the line segment that is nearest to the
        // point we want to test against
        lp_xyz[X] = p_xyz[X] - l_xyz[X];
        lp_xyz[Y] = p_xyz[Y] - l_xyz[Y];
        lp_xyz[Z] = p_xyz[Z] - l_xyz[Z];
        dot = dot_product(lm_xyz, lp_xyz);
        dot = (dot > 0.0f) ? dot : 0.0f;
        dot = (dot < length) ? dot : length;
        n_xyz[X] = l_xyz[X] + lm_xyz[X]*dot;
        n_xyz[Y] = l_xyz[Y] + lm_xyz[Y]*dot;
        n_xyz[Z] = l_xyz[Z] + lm_xyz[Z]*dot;

        // Determine the distance (squared) between our two points
        n_xyz[X] = p_xyz[X] - n_xyz[X];
        n_xyz[Y] = p_xyz[Y] - n_xyz[Y];
        n_xyz[Z] = p_xyz[Z] - n_xyz[Z];
        dis = n_xyz[X]*n_xyz[X] + n_xyz[Y]*n_xyz[Y] + n_xyz[Z]*n_xyz[Z];
    }
    else
    {
        // We're dealing with just a point/point distance...
        n_xyz[X] = p_xyz[X] - m_xyz[X];
        n_xyz[Y] = p_xyz[Y] - m_xyz[Y];
        n_xyz[Z] = p_xyz[Z] - m_xyz[Z];
        dis = n_xyz[X]*n_xyz[X] + n_xyz[Y]*n_xyz[Y] + n_xyz[Z]*n_xyz[Z];
    }
    return dis;
}

//------------------------------------------------------------------------------------
unsigned short collide_point_plane(float* m_xyz, float* p_xyz, float* plane_normal_xyz, float* intersection_xyz)
{
    // <ZZ> This function projects a point (m) onto a plane (p).
    //
    //      Returns 1 if the m point of the line segment is on the positive side of the
    //      plane.
    float pm_xyz[3];
    float dot_pm;
    float dis;

    pm_xyz[X] = m_xyz[X] - p_xyz[X];
    pm_xyz[Y] = m_xyz[Y] - p_xyz[Y];
    pm_xyz[Z] = m_xyz[Z] - p_xyz[Z];
    dot_pm = dot_product(pm_xyz, plane_normal_xyz);
    dis = dot_product(plane_normal_xyz, plane_normal_xyz);

    // Now, dot/dis should give us the percent...
    if(dis > 0.0f)
    {
        dis = dot_pm/dis;
        intersection_xyz[X] = m_xyz[X] - plane_normal_xyz[X]*dis;
        intersection_xyz[Y] = m_xyz[Y] - plane_normal_xyz[Y]*dis;
        intersection_xyz[Z] = m_xyz[Z] - plane_normal_xyz[Z]*dis;
    }
    else
    {
        intersection_xyz[X] = p_xyz[X];
        intersection_xyz[Y] = p_xyz[Y];
        intersection_xyz[Z] = p_xyz[Z];
    }

    // Determine our return value, based on which side of the plane m is on...
    if(dot_pm > 0.0f)
    {
        return 1;
    }
    return 0;
}

//------------------------------------------------------------------------------------
unsigned short collide_line_plane(float* l_xyz, float* m_xyz, float* p_xyz, float* plane_normal_xyz, float* intersection_xyz)
{
    // <ZZ> This function determines the point of intersection of a line (not a line
    //      segment)and a plane.  If the two are parallel, it fudges it to return an
    //      intersection anyway.  plane_normal_xyz doesn't need to be normalized...
    //
    //      Returns 1 if the m point of the line segment is on the positive side of the
    //      plane.
    float lm_xyz[3];
    float lp_xyz[3];
    float pm_xyz[3];
    float dot_lm;
    float dot_lp;
    float dot_pm;
    float dis;

    lm_xyz[X] = m_xyz[X] - l_xyz[X];
    lm_xyz[Y] = m_xyz[Y] - l_xyz[Y];
    lm_xyz[Z] = m_xyz[Z] - l_xyz[Z];
    lp_xyz[X] = p_xyz[X] - l_xyz[X];
    lp_xyz[Y] = p_xyz[Y] - l_xyz[Y];
    lp_xyz[Z] = p_xyz[Z] - l_xyz[Z];
    pm_xyz[X] = m_xyz[X] - p_xyz[X];
    pm_xyz[Y] = m_xyz[Y] - p_xyz[Y];
    pm_xyz[Z] = m_xyz[Z] - p_xyz[Z];


    // Dot each with the planar normal...
    dot_lm = dot_product(lm_xyz, plane_normal_xyz);
    dot_lp = dot_product(lp_xyz, plane_normal_xyz);
    dot_pm = dot_product(pm_xyz, plane_normal_xyz);


    // Fudge our one value, to prevent parallel lines...
    if(dot_lm > -0.00000000001f || dot_lm < 0.00000000001f)
    {
        dot_lm += 0.00000000002f;
    }


    // Now, lm/lp should give us the percent along lm that our intersection
    // point is...
    dis = (dot_lp / dot_lm);
    intersection_xyz[X] = l_xyz[X] + lm_xyz[X]*dis;
    intersection_xyz[Y] = l_xyz[Y] + lm_xyz[Y]*dis;
    intersection_xyz[Z] = l_xyz[Z] + lm_xyz[Z]*dis;


    // Determine our return value, based on which side of the plane m is on...
    if(dot_pm > 0.0f)
    {
        return 1;
    }
    return 0;
}

//------------------------------------------------------------------------------------
float collide_cylinder_triangle(float* l_xyz, float* m_xyz, float radius, float* a_xyz, float* b_xyz, float* c_xyz, float* triangle_normal_xyz)
{
    // <ZZ> This function determines whether a given cylinder (with ball caps) intersects a given
    //      triangle.  If they do not intersect, it returns a negative number.  If they do
    //      intersect, the function returns a positive number that indicates how far into the
    //      triangle (roughly) the cylinder is pressing.  l_xyz and m_xyz give the end points
    //      of the cylinder.  a_xyz, b_xyz, and c_xyz tell us the three points of the
    //      triangle.  triangle_normal_xyz tells us the normal vector of the plane of the
    //      triangle (which we computed earlier).  radius is the radius of the cylinder.
    //      
    //      This function works by finding the point on the plane of the triangle at which the
    //      line segment would intersect if it were a continuous line.  If that point is within
    //      the triangle, the minimum distance from that point to the line segment is calculated.
    //      We also find the point along each edge of the triangle that is nearest to the line
    //      segment -- and the minimum distance is calculated for each.  If the minimum distance
    //      is less than the radius, we have a collision.
    //
    //      The coordinates of the test point which was found to exist within the ball-capped
    //      cylinder is made available as a global...
    float lm_xyz[3];
    float i_xyz[4][3];
    float ab_xyz[3];
    float bc_xyz[3];
    float ca_xyz[3];
    float ab_normal_xyz[3];
    float bc_normal_xyz[3];
    float ca_normal_xyz[3];
    float temp_xyz[3];
    float lm_length;
    float dis, dot, temp;
    float radius_squared;
    int count;

//display_color(blue);
//display_start_line();
//    display_vertex_xyz(l_xyz[X], l_xyz[Y], l_xyz[Z]);
//    display_vertex_xyz(m_xyz[X], m_xyz[Y], m_xyz[Z]);
//display_end();



    // Determine the length of our line segment...
    lm_xyz[X] = m_xyz[X] - l_xyz[X];
    lm_xyz[Y] = m_xyz[Y] - l_xyz[Y];
    lm_xyz[Z] = m_xyz[Z] - l_xyz[Z];
    lm_length = lm_xyz[X]*lm_xyz[X] + lm_xyz[Y]*lm_xyz[Y] + lm_xyz[Z]*lm_xyz[Z];


    if(lm_length > 0.0f)
    {
        // Determine where this line segment would collide with the plane of the
        // triangle (if the line segment were long enough to do so)
        lm_length = (float) sqrt(lm_length);
        collide_line_plane(l_xyz, m_xyz, a_xyz, triangle_normal_xyz, i_xyz[0]);
    }
    else
    {
        // We're dealing with a really short line (basically a sphere)...
        // We'll do everything as above, but use the point function instead...
        collide_point_plane(m_xyz, a_xyz, triangle_normal_xyz, i_xyz[0]);
    }


    // Make sure neither of the end points are closer than our projected intersection point...
    // If they are, we should use those instead...
    dis = collide_point_line(i_xyz[0], l_xyz, m_xyz, lm_length);
    collide_point_plane(m_xyz, a_xyz, triangle_normal_xyz, i_xyz[1]);
    dot = collide_point_line(i_xyz[1], l_xyz, m_xyz, lm_length);
    if(dot < dis)
    {
        i_xyz[0][X] = i_xyz[1][X];
        i_xyz[0][Y] = i_xyz[1][Y];
        i_xyz[0][Z] = i_xyz[1][Z];
    }
    collide_point_plane(l_xyz, a_xyz, triangle_normal_xyz, i_xyz[1]);
    dot = collide_point_line(i_xyz[1], l_xyz, m_xyz, lm_length);
    if(dot < dis)
    {
        i_xyz[0][X] = i_xyz[1][X];
        i_xyz[0][Y] = i_xyz[1][Y];
        i_xyz[0][Z] = i_xyz[1][Z];
    }



    // Extrude each side of the triangle upwards along its normal -- calculate
    // the normal to each of those side extrusions...
    ab_xyz[X] = b_xyz[X] - a_xyz[X];
    ab_xyz[Y] = b_xyz[Y] - a_xyz[Y];
    ab_xyz[Z] = b_xyz[Z] - a_xyz[Z];
    bc_xyz[X] = c_xyz[X] - b_xyz[X];
    bc_xyz[Y] = c_xyz[Y] - b_xyz[Y];
    bc_xyz[Z] = c_xyz[Z] - b_xyz[Z];
    ca_xyz[X] = a_xyz[X] - c_xyz[X];
    ca_xyz[Y] = a_xyz[Y] - c_xyz[Y];
    ca_xyz[Z] = a_xyz[Z] - c_xyz[Z];
    cross_product(triangle_normal_xyz, ab_xyz, ab_normal_xyz);
    cross_product(triangle_normal_xyz, bc_xyz, bc_normal_xyz);
    cross_product(triangle_normal_xyz, ca_xyz, ca_normal_xyz);




    // Determine the nearest point along triangle edge ab to our line segment
    // We'll find this by using the line from the c corner of the triangle to the
    // intersection point.  Where that crosses ab...
    // While we do this, we're also keeping a count value around to determine whether
    // or not the first intersection point was within the triangle...
    count = 0;
    count += collide_line_plane(c_xyz, i_xyz[0], a_xyz, ab_normal_xyz, i_xyz[1]);

    // Determine the nearest point along triangle edge bc to our line segment
    count += collide_line_plane(a_xyz, i_xyz[0], b_xyz, bc_normal_xyz, i_xyz[2]);

    // Determine the nearest point along triangle edge ca to our line segment
    count += collide_line_plane(b_xyz, i_xyz[0], c_xyz, ca_normal_xyz, i_xyz[3]);



    // Was the first intersection point within the triangle?
    if(count < 3)
    {
        // No it wasn't, so we'll want to find which edge point is the best to use...
        // Is the ab side intersection point our best one?
        temp_xyz[X] = i_xyz[1][X] - a_xyz[X];
        temp_xyz[Y] = i_xyz[1][Y] - a_xyz[Y];
        temp_xyz[Z] = i_xyz[1][Z] - a_xyz[Z];
        dis = dot_product(temp_xyz, ab_xyz);
        dot = dot_product(ab_xyz, ab_xyz);
        if(dis <= dot && dis >= 0.0f)
        {
            // This is our best intersection point...
            i_xyz[0][X] = i_xyz[1][X];
            i_xyz[0][Y] = i_xyz[1][Y];
            i_xyz[0][Z] = i_xyz[1][Z];
        }
        else
        {
            // Is the bc side intersection point our best one?
            temp_xyz[X] = i_xyz[2][X] - b_xyz[X];
            temp_xyz[Y] = i_xyz[2][Y] - b_xyz[Y];
            temp_xyz[Z] = i_xyz[2][Z] - b_xyz[Z];
            dis = dot_product(temp_xyz, bc_xyz);
            dot = dot_product(bc_xyz, bc_xyz);
            if(dis <= dot && dis >= 0.0f)
            {
                // This is our best intersection point...
                i_xyz[0][X] = i_xyz[2][X];
                i_xyz[0][Y] = i_xyz[2][Y];
                i_xyz[0][Z] = i_xyz[2][Z];
            }
            else
            {
                // The other one must be the best...
                i_xyz[0][X] = i_xyz[3][X];
                i_xyz[0][Y] = i_xyz[3][Y];
                i_xyz[0][Z] = i_xyz[3][Z];
            }
        }
    }


    // Square the radius...
    radius_squared = radius*radius;


    // Now, determine the minimum distance from the best intersection
    // point to the line segment
    dis = collide_point_line(i_xyz[0], l_xyz, m_xyz, lm_length);
//global_testing = (float) sqrt(dis);
//    if(debug_draw)
//    {
//        display_marker(green, i_xyz[0][X], i_xyz[0][Y], i_xyz[0][Z], 0.50f);
//    }

    // Did we have a collision?
    if(dis < radius_squared)
    {
        // Yes we did, but the distance we report will depend on the type
        // of collision we had...
        global_collision_xyz[X] = i_xyz[0][X];
        global_collision_xyz[Y] = i_xyz[0][Y];
        global_collision_xyz[Z] = i_xyz[0][Z];

temp = collide_line_triangle(l_xyz, m_xyz, a_xyz, b_xyz, c_xyz, triangle_normal_xyz);
if(temp > 0.0f)
{
    dis = (2.0f*radius) - ((float) sqrt(dis));
}
else
{
    dis = radius - ((float) sqrt(dis));
}


global_collision_backface = FALSE;



if(lm_length > 0.0f)
{
    temp_xyz[X] = i_xyz[0][X] - l_xyz[X];
    temp_xyz[Y] = i_xyz[0][Y] - l_xyz[Y];
    temp_xyz[Z] = i_xyz[0][Z] - l_xyz[Z];
    lm_xyz[X]/=lm_length;
    lm_xyz[Y]/=lm_length;
    lm_xyz[Z]/=lm_length;
    dot = dot_product(lm_xyz, temp_xyz);
    global_collision_percent = dot/lm_length;
    global_collision_percent = (global_collision_percent < 0.0f) ? 0.0f : global_collision_percent;
    global_collision_percent = (global_collision_percent > 1.0f) ? 1.0f : global_collision_percent;
}

        return dis;
    }

    // Looks like we didn't have any collision between this ball-capped
    // cylinder and this triangle...
    return -1.0f;
}

//------------------------------------------------------------------------------------
