[an error occurred while processing this directive]
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//
//  Project:   Talina Gaming System (TgS) (∂)
//  File:      TgS Collision - Box AA-Sphere.cpp
//  Author:    Andrew Aye (EMail: andrew.aye@gmail.com, Web: http://www.andrewaye.com) 
//  Version:   3.11
//
// ------------------------------------------------------------------------------------------------------------------------------ //
//
//  Copyright: © 2002-2008, Andrew Aye.  All Rights Reserved.
//
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //




namespace TGS { // START TGS ///////////////////////////////////////////////////////////////////////////////////////////////////////
namespace COL { // START COL ///////////////////////////////////////////////////////////////////////////////////////////////////////

// ============================================================================================================================== //

// ---- F_Contact_Penetrate ----------------------------------------------------------------------------------------------------- //
// Input:  tgPacket: The current series of contact points for this query-series, and contact generation parameters.
// Input:  tgSP0: Sphere primitive
// Input:  tgBA0: Box, Axis-Aligned primitive - contact points are generated on this primitive
// Output: tgPacket: Points of penetration between the two primitives are added to it
// Return: Result Code
// ------------------------------------------------------------------------------------------------------------------------------ //

template <typename TYPE, int DIM>
TgRESULT F_Contact_Penetrate( PC_(CONTACT_PACKET,DIM) ptgPacket, CR_(SPHERE,DIM) tgSP0, CR_(BOXAA,DIM) tgBA0 )
{
    TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_PENETRATE, (((TgUINT)ETgSPHERE<<16)|(TgUINT)ETgBOXAA))

    TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) ))
    TgASSERT(tgBA0.Is_Valid() && tgSP0.Is_Valid())

    if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact)
    {
        return (TgE_FAIL);
    };

    //  Find the point of closest proximity on the box to the sphere's origin and create a normalized direction vector of the
    // difference between the two points.  These are the potential contact points and normal.

    M_(VECTOR,DIM)                     tvS0 = tgSP0.Query_Origin();
    T_(VECTOR,DIM)                      tvP1, tvNormal;
    P_(CONTACT,DIM)                     ptgContact;

    const TYPE                          tyX00 = tvS0.X() - tgBA0.Query_MinX();
    const TYPE                          tyX01 = tgBA0.Query_MaxX() - tvS0.X();
    const TYPE                          tyX10 = tvS0.Y() - tgBA0.Query_MinY();
    const TYPE                          tyX11 = tgBA0.Query_MaxY() - tvS0.Y();
    const TYPE                          tyX20 = tvS0.Z() - tgBA0.Query_MinZ();
    const TYPE                          tyX21 = tgBA0.Query_MaxZ() - tvS0.Z();

    const TYPE                          tyX = P::FSEL( tyX00, P::FSEL( tyX01, tvP1.X(), tgBA0.Query_MaxX() ), tgBA0.Query_MinX() );
    const TYPE                          tyY = P::FSEL( tyX10, P::FSEL( tyX11, tvP1.Y(), tgBA0.Query_MaxY() ), tgBA0.Query_MinY() );
    const TYPE                          tyZ = P::FSEL( tyX20, P::FSEL( tyX21, tvP1.Z(), tgBA0.Query_MaxZ() ), tgBA0.Query_MinZ() );

    tvP1 = MATH::F_SETP<TYPE,DIM>( tyX,tyY,tyZ );
    tvNormal = MATH::F_SUB( tvP1, tgSP0.Query_Origin() );

    ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);

    if (MATH::F_LSQ( tvNormal ) > LIMITS<TYPE>::EPSILON)
    {
        TYPE                                tyNM;

        tvNormal = MATH::F_NORM( &tyNM, tvNormal );

        if (tyNM > LIMITS<TYPE>::EPSILON)
        {
            // Sphere origin is not contained inside of the box, and therefore the potential contact values are correct.

            ptgContact->m_tvPos = tvP1;
            ptgContact->m_tvNormal = tvNormal;
            ptgContact->m_tyT0 = TYPE(0.0);
            ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyNM;

            ++ptgPacket->m_niContact;

            return (TgS_OK);
        };
    };

    // Sphere origin is contained within the box itself - find the axis of minimum penetration.

    const TYPE                          tyX0 = P::FSEL( tyX01 - tyX00, tyX00, tyX01 );
    const TYPE                          tyX1 = P::FSEL( tyX11 - tyX10, tyX10, tyX11 );
    const TYPE                          tyX2 = P::FSEL( tyX21 - tyX20, tyX20, tyX21 );

    const TYPE                          tyK0 = tyX1 - tyX0;
    const TYPE                          tyK1 = tyX2 - tyX0;
    const TYPE                          tyK2 = tyX2 - tyX1;

    const TYPE                          tyTX = P::FSEL( tyX01 - tyX00, tgBA0.Query_MinX(), tgBA0.Query_MaxX() );
    const TYPE                          tyTY = P::FSEL( tyX11 - tyX10, tgBA0.Query_MinY(), tgBA0.Query_MaxY() );
    const TYPE                          tyTZ = P::FSEL( tyX21 - tyX20, tgBA0.Query_MinZ(), tgBA0.Query_MaxZ() );

    const TYPE                          tyKTX = P::FSEL( tyK0, P::FSEL( tyK1, tyTX, tvS0.X() ), tvS0.X() );
    const TYPE                          tyKTY = P::FSEL( tyK0, tvS0.Y(), P::FSEL( tyK2, tyTY, tvS0.Y() ) );
    const TYPE                          tyKTZ = P::FSEL( tyK0, P::FSEL( tyK1, tvS0.X(), tyTZ ), P::FSEL( tyK2, tvS0.Z(), tyTZ ) );

    const TYPE                          tyNX = P::FSEL( tyX01 - tyX00, TYPE(1.0), TYPE(-1.0) );
    const TYPE                          tyNY = P::FSEL( tyX11 - tyX10, TYPE(1.0), TYPE(-1.0) );
    const TYPE                          tyNZ = P::FSEL( tyX21 - tyX20, TYPE(1.0), TYPE(-1.0) );

    const TYPE                          tyKNX = P::FSEL( tyK0, P::FSEL( tyK1, tyNX, TYPE() ), TYPE() );
    const TYPE                          tyKNY = P::FSEL( tyK0, TYPE(), P::FSEL( tyK2, tyNY, TYPE() ) );
    const TYPE                          tyKNZ = P::FSEL( tyK0, P::FSEL( tyK1, TYPE(), tyNZ ), P::FSEL( tyK2, TYPE(), tyNZ ) );

    ptgContact->m_tvPos = MATH::F_SETP<TYPE,DIM>( tyKTX,tyKTY,tyKTZ );
    ptgContact->m_tvNormal = MATH::F_SETV<TYPE,DIM>( tyKNX,tyKNY,tyKNZ );
    ptgContact->m_tyT0 = TYPE(0.0);
    ptgContact->m_tyDepth = tgSP0.Query_Radius() + P::FSEL( tyK0, P::FSEL( tyK1, tyX0, tyX2 ), P::FSEL( tyK2, tyX1, tyX2 ) );

    ++ptgPacket->m_niContact;
    return (TgS_OK);
};

template TgRESULT F_Contact_Penetrate( PC_TgF4CONTACT_PACKET, CR_TgF4SPHERE, CR_TgF4BOXAA );


// ============================================================================================================================== //

}; // END COL //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}; // END TGS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[an error occurred while processing this directive]