[an error occurred while processing this directive]
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // // // Project: Talina Gaming System (TgS) (∂) // File: TgS Collision - Box-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: tgBX1: Box 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_(BOX,DIM) tgBX1 ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_PENETRATE, (((TgUINT)ETgSPHERE<<16)|(TgUINT)ETgBOX)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgBX1.Is_Valid() && tgSP0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; T_(VECTOR,DIM) tvDS = MATH::F_SUB( tgSP0.Query_Origin(), tgBX1.Query_Origin() ); // Difference vector in box's reference frame. const TYPE tyT0 = MATH::F_DOT( tvDS, tgBX1.Query_AxisUnit0() ); const TYPE tyT1 = MATH::F_DOT( tvDS, tgBX1.Query_AxisUnit1() ); const TYPE tyT2 = MATH::F_DOT( tvDS, tgBX1.Query_AxisUnit2() ); // A measurement of how far the sphere's origin is from a box face. Negative is contained in box. const TYPE tyX0 = P::ABS( tyT0 ) - tgBX1.Query_Extent0(); const TYPE tyX1 = P::ABS( tyT1 ) - tgBX1.Query_Extent1(); const TYPE tyX2 = P::ABS( tyT2 ) - tgBX1.Query_Extent2(); if (tyX0 > tgSP0.Query_Radius() || tyX1 > tgSP0.Query_Radius() || tyX2 > tgSP0.Query_Radius()) { // If the sphere is at worst radius away from every box face, then their is no penetration. return (TgE_NOINTERSECT); }; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); const TYPE tyK0 = tgBX1.Query_Extent0(); const TYPE tyK1 = tgBX1.Query_Extent1(); const TYPE tyK2 = tgBX1.Query_Extent2(); const TYPE tyP0 = P::FSEL( tyX0, P::FSEL( tyT0, tyK0, -tyK0 ), tyT0 ); const TYPE tyP1 = P::FSEL( tyX1, P::FSEL( tyT1, tyK1, -tyK1 ), tyT1 ); const TYPE tyP2 = P::FSEL( tyX2, P::FSEL( tyT2, tyK2, -tyK2 ), tyT2 ); ptgContact->m_tvPos = tgBX1.Calc_Point( tyP0,tyP1,tyP2 ); if (tyX0 > TYPE(0.0) || tyX1 > TYPE(0.0) || tyX2 > TYPE(0.0)) { // If the origin lies outside even one face then calculating the penetration contact is done by simply creating the point // of closest proximity on the box to the sphere origin. This point is the contact point, and the vector difference is the // normal of contact. TYPE tyK6; ptgContact->m_tvNormal = MATH::F_NORM( &tyK6, MATH::F_SUB( tgBX1.Calc_Point( tyP0,tyP1,tyP2 ), tgSP0.Query_Origin() ) ); ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyK6; ++ptgPacket->m_niContact; return (TgS_OK); }; // The sphere origin must be contained within the box. Penetration is determined by finding the axis of minimum penetration // and creating a contact to eject the sphere out of the nearest face aligned with that axis. All of the measurements must // be negative (ie the point is contained), thus, it is the least negative (or the greatest value) that determines the axis // what has the minimal penetration. if (tyX0 > tyX1) { if (tyX0 > tyX2) { ptgContact->m_tvPos(0) = tyT0 < TYPE(0.0) ? -tgBX1.Query_Extent0() : tgBX1.Query_Extent0(); ptgContact->m_tvNormal = tyT0 > TYPE(0.0) ? MATH::F_NEG( tgBX1.Query_AxisUnit0() ) : tgBX1.Query_AxisUnit0(); ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyX0; ++ptgPacket->m_niContact; return (TgS_OK); } else { ptgContact->m_tvPos(2) = tyT2 < TYPE(0.0) ? -tgBX1.Query_Extent2() : tgBX1.Query_Extent2(); ptgContact->m_tvNormal = tyT2 > TYPE(0.0) ? MATH::F_NEG( tgBX1.Query_AxisUnit2() ) : tgBX1.Query_AxisUnit2(); ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyX2; ++ptgPacket->m_niContact; return (TgS_OK); }; } else { if (tyX1 > tyX2) { ptgContact->m_tvPos(1) = tyT1 < TYPE(0.0) ? -tgBX1.Query_Extent1() : tgBX1.Query_Extent1(); ptgContact->m_tvNormal = tyT1 > TYPE(0.0) ? MATH::F_NEG( tgBX1.Query_AxisUnit1() ) : tgBX1.Query_AxisUnit1(); ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyX1; ++ptgPacket->m_niContact; return (TgS_OK); } else { ptgContact->m_tvPos(2) = tyT2 < TYPE(0.0) ? -tgBX1.Query_Extent2() : tgBX1.Query_Extent2(); ptgContact->m_tvNormal = tyT2 > TYPE(0.0) ? MATH::F_NEG( tgBX1.Query_AxisUnit2() ) : tgBX1.Query_AxisUnit2(); ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgSP0.Query_Radius() - tyX2; ++ptgPacket->m_niContact; return (TgS_OK); }; }; return (TgE_FAIL); }; template TgRESULT F_Contact_Penetrate( PC_TgF4CONTACT_PACKET, CR_TgF4SPHERE, CR_TgF4BOX ); // ============================================================================================================================== // }; // END COL ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }; // END TGS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[an error occurred while processing this directive]