[an error occurred while processing this directive]
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // // // Project: Talina Gaming System (TgS) (∂) // File: TgS Collision - Cylinder-Capsule.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_Axis_Seperation ------------------------------------------------------------------------------------------------------- // // Input: tgCP0: Capsule primitive // Input: tgCY0: Cylinder primitive // Output: tgAxS: Structure holds the resulting axis separation information necessary to create a contact set. // Return: False if a separating axis exists, true otherwise // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgBOOL F_Axis_Seperation( PC_(AXIS_RESULT,DIM) ptgAxS, CR_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0 ) { TgASSERT( tgCP0.Is_Valid() && tgCY0.Is_Valid() ) TYPE tyTest; T_(VECTOR,DIM) tvTest; // Construct the difference vector between the two origins and calculate the reference frame projections. C_(VECTOR,DIM) tvDS = MATH::F_SUB( tgCY0.Query_Origin(), tgCP0.Query_Origin() ); //const TYPE tyDS_A0 = MATH::F_DOT( tvDS, tgCP0.Query_AxisUnit() ); const TYPE tyDS_A1 = MATH::F_DOT( tvDS, tgCY0.Query_AxisUnit() ); // == Axis Separation Tests ============================================================== ptgAxS->m_tyDepth = -LIMITS<TYPE>::MAX; const TYPE tyABS_A0_A1 = P::ABS( MATH::F_DOT( tgCP0.Query_AxisUnit(), tgCY0.Query_AxisUnit() ) ); // -- Axis: Cylinder Axes ---------------------------------- // Cylinder #0 Axis tyTest = P::ABS( tyDS_A1 ) - (tgCY0.Query_Extent() + tgCP0.Query_Radius() + tgCP0.Query_Extent()*tyABS_A0_A1); if (tyTest > TYPE(0.0)) { return (TgFALSE); }; if (tyTest > ptgAxS->m_tyDepth) { ptgAxS->m_tvNormal = tyDS_A1 > TYPE(0.0) ? tgCY0.Query_AxisUnit() : MATH::F_NEG( tgCY0.Query_AxisUnit() ); ptgAxS->m_tyDepth = tyTest; ptgAxS->m_iAxis = 1; }; // --------------------------------------------------------- const TYPE tyRadSum = tgCP0.Query_Radius() + tgCY0.Query_Radius(); CR_(SEGMENT,DIM) tgSG_CP0 = tgCP0.Query_Segment(); CR_(SEGMENT,DIM) tgSG_CY0 = tgCY0.Query_Segment(); TYPE tyCA0,tyCA1, tyC0,tyC1, tyTMPA; const TYPE tyDistSq = F_ClosestSq( &tyCA0, &tyCA1, tgSG_CP0, tgSG_CY0 ); if (tyDistSq > tyRadSum*tyRadSum) { return (TgFALSE); }; C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tyCA0, tgSG_CP0.Query_DirN() ); C_(VECTOR,DIM) tvK1 = MATH::F_MUL( tyCA1, tgSG_CY0.Query_DirN() ); C_(VECTOR,DIM) tvMin_CP0 = MATH::F_ADD( tgSG_CP0.Query_Origin(), tvK0 ); C_(VECTOR,DIM) tvMin_CY0 = MATH::F_ADD( tgSG_CY0.Query_Origin(), tvK1 ); T_(VECTOR,DIM) tvMinDirN; TgBOOL bIntersecting = TgTRUE; if (tyDistSq > LIMITS<TYPE>::EPSILON) { C_(VECTOR,DIM) tvMinDist = MATH::F_SUB( tvMin_CY0, tvMin_CP0 ); tvMinDirN = MATH::F_SUB( tvMin_CY0, tvMin_CP0 ); MATH::F_NORM( tvMinDirN ); // -- Axis: Direction Between Points of Closest Proximity -- TYPE tyT0,tyT1, tyT2,tyT3; tgCP0.Project( &tyT0,&tyT1, tvMinDirN ); tgCY0.Project( &tyT2,&tyT3, tvMinDirN ); if (tyT1 - tyT2 < TYPE(0.0) || tyT3 - tyT0 < TYPE(0.0)) { return (TgFALSE); }; tyTest = tyT2 - tyT1; if (tyTest > ptgAxS->m_tyDepth) { ptgAxS->m_tvPoint = tvMin_CY0; ptgAxS->m_tvNormal = tvMinDirN; ptgAxS->m_tyDepth = tyTest; ptgAxS->m_iAxis = 2; }; } else { TYPE tyTest; bIntersecting = TgFALSE; tvMinDirN = MATH::F_NORM( &tyTest, tvDS ); if (Near_Zero( tyTest )) { // That's it - throw in the towel, I give up - these primitives are just too penetrated to care which axis is used. return (TgTRUE); }; }; // -- Axis: Perpendicular to Axis of Cylinder -------------- tyC0 = MATH::F_DOT( tvMinDirN, tgCY0.Query_BasisUnit0() ); tyC1 = MATH::F_DOT( tvMinDirN, tgCY0.Query_BasisUnit1() ); C_(VECTOR,DIM) tvK2 = MATH::F_MUL( tyC0, tgCY0.Query_BasisUnit0() ); C_(VECTOR,DIM) tvK3 = MATH::F_MUL( tyC1, tgCY0.Query_BasisUnit1() ); tvTest = MATH::F_NORM( MATH::F_ADD( tvK2, tvK3 ) ); const TYPE tyABS_Ax_A0 = P::ABS( MATH::F_DOT(tvTest,tgCP0.Query_AxisUnit()) ); tyTest = P::ABS( MATH::F_DOT(tvTest,tvDS) ) - (tgCY0.Query_Radius() + tyABS_Ax_A0*tgCP0.Query_Extent() + tgCP0.Query_Radius()); if (tyTest > TYPE(0.0)) { return (TgFALSE); }; if (tyTest > ptgAxS->m_tyDepth) { ptgAxS->m_tvPoint = tvMin_CP0; ptgAxS->m_tvNormal = tvTest; ptgAxS->m_tyDepth = tyTest; ptgAxS->m_iAxis = 2; }; const TYPE tyABS_A0xA1 = P::SQRT( TYPE(1.0) - MIN( TYPE(1.0), tyABS_A0_A1*tyABS_A0_A1 ) ); if (!Near_One( tyABS_A0_A1 ) && !Near_Zero( tyABS_A0xA1 )) { // -- Axis: Perpendicular to Axis of Capsule --------------- tyC0 = MATH::F_DOT(tvMinDirN,tgCP0.Query_BasisUnit0()); tyC1 = MATH::F_DOT(tvMinDirN,tgCP0.Query_BasisUnit1()); C_(VECTOR,DIM) tvK4 = MATH::F_MUL( tyC0, tgCP0.Query_BasisUnit0() ); C_(VECTOR,DIM) tvK5 = MATH::F_MUL( tyC1, tgCP0.Query_BasisUnit1() ); tvTest = MATH::F_NORM( MATH::F_ADD( tvK4, tvK5 ) ); const TYPE tyABS_Ax_A1 = P::ABS( MATH::F_DOT(tvTest,tgCY0.Query_AxisUnit()) ); const TYPE tyAx_C10 = MATH::F_DOT(tvTest,tgCY0.Query_BasisUnit0()); const TYPE tyAx_C11 = MATH::F_DOT(tvTest,tgCY0.Query_BasisUnit1()); const TYPE tyK0 = tgCP0.Query_Radius() + tyABS_Ax_A1*tgCY0.Query_Extent(); tyTMPA = P::SQRT( tyAx_C10*tyAx_C10 + tyAx_C11*tyAx_C11 ); tyTest = P::ABS( MATH::F_DOT( tvTest, tvDS ) ) - (tyK0 + tyTMPA*tgCY0.Query_Radius()); if (tyTest > TYPE(0.0)) { return (TgFALSE); }; if (tyTest > ptgAxS->m_tyDepth) { ptgAxS->m_tvPoint = tvMin_CY0; ptgAxS->m_tvNormal = tvTest; ptgAxS->m_tyDepth = tyTest; ptgAxS->m_iAxis = 2; }; }; // !! VOODOO MAGIC TIME !! - Red Red Wine, Drink a lot of it before proceeding, I'm telling you man - get snookered. // Need to try to test the rim cases - <shot> if (Near_One( tyCA1 ) || Near_Zero( tyCA1 )) { TYPE tyT0,tyT1, tyT2,tyT3; T_(VECTOR,DIM) tvCI0, tvSG0; CR_(SEGMENT,DIM) tgSG_CP0 = tgCP0.Query_Segment(); const TYPE tyDistSq = TTgCSQ_CILN<TYPE,DIM,1,1>::DO( &tvCI0,&tvSG0, tvMin_CY0,tgCY0.Query_AxisUnit(), tgCY0.Query_Radius(), tgSG_CP0.Query_Origin(), tgSG_CP0.Query_DirN() ); if (tyDistSq < TYPE(0.0)) { return (TgTRUE); }; tvTest = MATH::F_NORM( MATH::F_SUB( tvCI0, tvSG0 ) ); tgCP0.Project( &tyT0,&tyT1, tvTest ); tgCY0.Project( &tyT2,&tyT3, tvTest ); if (tyT1 - tyT2 < TYPE(0.0) || tyT3 - tyT0 < TYPE(0.0)) { return (TgFALSE); }; tyTest = tyT2 - tyT1; if (tyTest > ptgAxS->m_tyDepth) { ptgAxS->m_tvPoint = tvCI0; ptgAxS->m_tvNormal = tvTest; ptgAxS->m_tyDepth = tyTest; ptgAxS->m_iAxis = 3; }; }; return (TgTRUE); }; template TgBOOL F_Axis_Seperation( PC_TgF4AXIS_RESULT, CR_TgF4CAPSULE, CR_TgF4CYLINDER ); // ============================================================================================================================== // // ---- F_Contact_Penetrate_CylAxis --------------------------------------------------------------------------------------------- // // -- Internal Function -- // Input: tgPacket: The current series of contact points for this query-series, and contact generation parameters. // Input: tgAxS: Structure holding the resulting axis separation information necessary to create a contact set. // Input: tgCP0: Capsule primitive // Input: tgCY0: Cylinder 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_CylAxis( PC_(CONTACT_PACKET,DIM) ptgPacket, CR_(AXIS_RESULT,DIM) tgAxS, CR_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0 ) { // (1) Capsule is contained within the infinite projection of the cylinder (tube) // (2) Capsule axis termination is contained but also passes through the cylinder (tube). // (3) Capsule passes through-and-through the cylinder (tube) // (4) Capsule axis is entirely outside of the cylinder - the only intersecting part is the capsule cap. C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tgCY0.Query_Extent(), tgAxS.m_tvNormal ); C_(VECTOR,DIM) tvCYC = MATH::F_SUB( tgCY0.Query_Origin(), tvK0 ); const TYPE tyAX_N = MATH::F_DOT( tgCP0.Query_AxisUnit(), tgAxS.m_tvNormal ); C_TgINT niContact = ptgPacket->m_niContact; P_(CONTACT,DIM) ptgContact; T_(VECTOR,DIM) tvCPC, tvTest; TYPE tyTest; // Attempt to create a contact point at the lowest point on the capsule. C_(VECTOR,DIM) tvK2 = MATH::F_MUL( P::FSEL( tyAX_N, TYPE(1.0), TYPE(-1.0) ), tgCP0.Query_HalfAxis() ); tvCPC = MATH::F_ADD( tgCP0.Query_Origin(), tvK2 ); tyTest = MATH::F_DOT( MATH::F_SUB( tvCPC, tvCYC ), tgAxS.m_tvNormal ); if (tyTest > TYPE(0.0) && tgCY0.Is_Contained( tvCPC )) { // Capsule termination is a contact point ([Case: 1,2]) ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = MATH::F_ADD( tvCPC, MATH::F_MUL( tgCP0.Query_Radius(), tgAxS.m_tvNormal ) ); ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tyTest; ++ptgPacket->m_niContact; }; // Construct a capsule axis that is directed for maximum penetration into the cylinder. M_(VECTOR,DIM) tvBX0 = tgCP0.Query_BasisUnit0(); M_(VECTOR,DIM) tvBX1 = tgCP0.Query_BasisUnit1(); T_(VECTOR,DIM) tvT0, tvX0; TYPE tyX,tyY,tyZ, tyT0,tyT1; const TYPE tyUseBX = P::ABS( tyAX_N ) - (TYPE(1.0) - LIMITS<TYPE>::EPSILON); tvT0 = MATH::F_SUB( tgAxS.m_tvNormal, MATH::F_MUL( tyAX_N, tgCP0.Query_AxisUnit() ) ); tyX = P::FSEL( tyUseBX, tvBX0.X(), tvT0.X() ); tyY = P::FSEL( tyUseBX, tvBX0.Y(), tvT0.Y() ); tyZ = P::FSEL( tyUseBX, tvBX0.Z(), tvT0.Z() ); tvX0 = MATH::F_NORM( MATH::F_SETV<TYPE,DIM>( tyX,tyY,tyZ ) ); // Translate the capsule axis to the line of deepest penetration along the capsule, and then clip it to the cylinder. T_(SEGMENT,DIM) tgCPAX = tgCP0.Query_Segment(); tgCPAX.Set_Origin( MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tgCP0.Query_Radius(), tvX0 ) ) ); if (F_Clip( &tyT0,&tyT1, tgCY0,tgCPAX ) >= 0) { tvTest = MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tyT0, tgCPAX.Query_DirN() ) ); tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tvCYC ), tgAxS.m_tvNormal ); if (tyTest > TYPE(0.0) && niContact == ptgPacket->m_niContact) { if (ptgPacket->m_niContact >= ptgPacket->m_niMaxContact) { return (TgS_MAXCONTACTS); }; // Capsule termination is a contact point ([Case: 3]) ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tvTest; ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tyTest; ++ptgPacket->m_niContact; }; // Similar to above, and it must not be sufficiently divergent from the first point (prevent two-point tangents) tvTest = MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tyT1, tgCPAX.Query_DirN() ) ); tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tvCYC ), tgAxS.m_tvNormal ); if (tyTest > TYPE(0.0) && !Near_Zero( tyT0 - tyT1 )) { if (ptgPacket->m_niContact >= ptgPacket->m_niMaxContact) { return (TgS_MAXCONTACTS); }; // Capsule termination is a contact point ([Case: 1,2,3]) ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tvTest; ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tyTest; ++ptgPacket->m_niContact; }; return (niContact != ptgPacket->m_niContact ? TgS_OK : TgE_NOINTERSECT); }; // The capsule contact line is outside of the cylinder. Attempt to intersect the cylinder with the capsule. ([Case: 4]) // One of the extremes of the cylinder rim must be penetrated into the capsule. Therefore use math. C_(VECTOR,DIM) tvK1 = MATH::F_SUB( tgCP0.Query_AxisUnit(), MATH::F_MUL( tyAX_N, tgAxS.m_tvNormal ) ); tvX0 = MATH::F_NORM( MATH::F_MUL( P::FSEL( tyAX_N, TYPE(-1.0), TYPE(-1.0) ), tvK1 ) ); tvT0 = MATH::F_ADD( tvCYC, MATH::F_MUL( tgCY0.Query_Radius(), tvX0 ) ); tvTest = MATH::F_NORM( &tyTest, MATH::F_SUB( tvT0, tvCPC ) ); tyTest = MATH::F_DOT( tvTest, tgAxS.m_tvNormal ) * (tgCP0.Query_Radius() - tyTest); if (tyTest > TYPE(0.0)) { // Capsule termination is a contact point ([Case: 3]) ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tvT0; ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tyTest; ++ptgPacket->m_niContact; }; tvT0 = MATH::F_SUB( tvCYC, MATH::F_MUL( tgCY0.Query_Radius(), tvX0 ) ); tvTest = MATH::F_NORM( &tyTest, MATH::F_SUB( tvT0, tvCPC ) ); tyTest = MATH::F_DOT( tvTest, tgAxS.m_tvNormal ) * (tgCP0.Query_Radius() - tyTest); if (tyTest > TYPE(0.0)) { // Capsule termination is a contact point ([Case: 3]) ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tvT0; ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tyTest; ++ptgPacket->m_niContact; }; return (niContact != ptgPacket->m_niContact ? TgS_OK : TgE_NOINTERSECT); }; template TgRESULT F_Contact_Penetrate_CylAxis( PC_TgF4CONTACT_PACKET, CR_TgF4AXIS_RESULT, CR_TgF4CAPSULE, CR_TgF4CYLINDER ); // ============================================================================================================================== // // ---- F_Contact_Penetrate ----------------------------------------------------------------------------------------------------- // // Input: tgPacket: The current series of contact points for this query-series, and contact generation parameters. // Input: tgCP0: Capsule primitive // Input: tgCY0: Cylinder 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_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0 ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_PENETRATE, (((TgUINT)ETgCAPSULE<<16)|(TgUINT)ETgCYLINDER)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgCY0.Is_Valid() && tgCP0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; // Find the minimal axis of separation, or return if the primitives are not in contact. TTgAXIS_RESULT<TYPE,DIM> tgAxS; if (!F_Axis_Seperation( &tgAxS, tgCP0,tgCY0 )) { return (TgE_NOINTERSECT); }; TgASSERT( Near_One( MATH::F_LSQ(tgAxS.m_tvNormal) ) && tgAxS.m_tyDepth >= TYPE(0.0) ) // == Contact Generation ==================================================================================================== // //C_TgINT niContact = ptgPacket->m_niContact; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); switch (tgAxS.m_iAxis) { case 7: // -- Axis: Rim -------------------------------------------- ptgContact->m_tvPos = tgAxS.m_tvPoint; ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgAxS.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); case 2: { // -- Axis: Perpendicular to Axis of Cylinder -------------- T_(VECTOR,DIM) tvTest; TYPE tyTest; tvTest = tgCP0.Calc_Support_Point( tgAxS.m_tvNormal ); tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tgCY0.Query_Origin() ), tgAxS.m_tvNormal ) + tgCY0.Query_Radius(); if (tyTest <= TYPE(0.0)) { COUT_NOOBJ( WARNING, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithm: Separation Axis found with no contacts generated.\n"), TgT("Collision"), TgT("F_Contact_Penetrate") );; return (TgE_NOINTERSECT); }; ptgContact->m_tvPos = MATH::F_SUB( tvTest, MATH::F_MUL( tyTest, tgAxS.m_tvNormal ) ); ptgContact->m_tvNormal = tgAxS.m_tvNormal; ptgContact->m_tyT0 = TYPE(0.0); ptgContact->m_tyDepth = tgAxS.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); }; case 1: { // -- Axis: Cylinder Axis ---------------------------------- return (F_Contact_Penetrate_CylAxis( ptgPacket, tgAxS, tgCP0, tgCY0 )); }; default: COUT_NOOBJ( CRITICAL, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithmic - Should not be able to reach this location.\n"), TgT("Collision"), TgT("F_Contact_Penetrate") ); return (TgE_FAIL); }; COUT_NOOBJ( CRITICAL, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithmic - Should not be able to reach this location.\n"), TgT("Collision"), TgT("F_Contact_Penetrate") ); return (TgE_FAIL); }; template TgRESULT F_Contact_Penetrate( PC_TgF4CONTACT_PACKET, CR_TgF4CAPSULE, CR_TgF4CYLINDER ); // ============================================================================================================================== // }; // END COL ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }; // END TGS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[an error occurred while processing this directive]