int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
{
    dIASSERT( skip >= (int)sizeof( dContactGeom ) );
    dIASSERT( o1->type == dCylinderClass );
    dIASSERT( o2->type == dTriMeshClass );
    dIASSERT ((flags & NUMC_MASK) >= 1);

    // Main data holder
    sData cData;

    // Assign ODE stuff
    cData.gCylinder	 = o1;
    cData.gTrimesh	 = (dxTriMesh*)o2;
    cData.iFlags	 = flags;
    cData.iSkip		 = skip;
    cData.gContact	 = contact;
    cData.nContacts  = 0;

    _InitCylinderTrimeshData(cData);

//*****at first , collide box aabb******//

    aabb3f test_aabb;

    test_aabb.minX = o1->aabb[0];
    test_aabb.maxX = o1->aabb[1];
    test_aabb.minY = o1->aabb[2];
    test_aabb.maxY = o1->aabb[3];
    test_aabb.minZ = o1->aabb[4];
    test_aabb.maxZ = o1->aabb[5];


    GDYNAMIC_ARRAY collision_result;
    GIM_CREATE_BOXQUERY_LIST(collision_result);

    gim_aabbset_box_collision(&test_aabb, &cData.gTrimesh->m_collision_trimesh.m_aabbset , &collision_result);

    if(collision_result.m_size==0)
    {
        GIM_DYNARRAY_DESTROY(collision_result);
        return 0;
    }
//*****Set globals for box collision******//

    int ctContacts0 = 0;
    cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK));

    GUINT * boxesresult = GIM_DYNARRAY_POINTER(GUINT,collision_result);
    GIM_TRIMESH * ptrimesh = &cData.gTrimesh->m_collision_trimesh;

    gim_trimesh_locks_work_data(ptrimesh);


    for(unsigned int i=0; i<collision_result.m_size; i++)
    {
        const int Triint = boxesresult[i];

        dVector3 dv[3];
        gim_trimesh_get_triangle_vertices(ptrimesh, Triint,dv[0],dv[1],dv[2]);
        // test this triangle
        TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false);

        // fill-in triangle index for generated contacts
        for (; ctContacts0<cData.nContacts; ctContacts0++)
            cData.gLocalContacts[ctContacts0].triIndex =  Triint;

        // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue"
        if(cData.nContacts	>= (cData.iFlags & NUMC_MASK))
        {
            break;
        }
    }

    gim_trimesh_unlocks_work_data(ptrimesh);
    GIM_DYNARRAY_DESTROY(collision_result);

    return _ProcessLocalContacts(cData);
}
int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
{
    dIASSERT( skip >= (int)sizeof( dContactGeom ) );
    dIASSERT( o1->type == dCylinderClass );
    dIASSERT( o2->type == dTriMeshClass );
    dIASSERT ((flags & NUMC_MASK) >= 1);

    // Main data holder
    sData cData;

    // Assign ODE stuff
    cData.gCylinder	 = o1;
    cData.gTrimesh	 = (dxTriMesh*)o2;
    cData.iFlags	 = flags;
    cData.iSkip		 = skip;
    cData.gContact	 = contact;
    cData.nContacts  = 0;

    _InitCylinderTrimeshData(cData);

    OBBCollider& Collider = cData.gTrimesh->_OBBCollider;

    Point cCenter((float)cData.vCylinderPos[0],(float)cData.vCylinderPos[1],(float)cData.vCylinderPos[2]);

    Point cExtents((float)cData.fCylinderRadius,(float)cData.fCylinderRadius,(float)cData.fCylinderRadius);
    cExtents[nCYLINDER_AXIS] = (float)(cData.fCylinderSize * REAL(0.5));

    Matrix3x3 obbRot;

    // It is a potential issue to explicitly cast to float
    // if custom width floating point type is introduced in OPCODE.
    // It is necessary to make a typedef and cast to it
    // (e.g. typedef float opc_float;)
    // However I'm not sure in what header it should be added.

    obbRot[0][0] = (float)cData.mCylinderRot[0];
    obbRot[1][0] = (float)cData.mCylinderRot[1];
    obbRot[2][0] = (float)cData.mCylinderRot[2];

    obbRot[0][1] = (float)cData.mCylinderRot[4];
    obbRot[1][1] = (float)cData.mCylinderRot[5];
    obbRot[2][1] = (float)cData.mCylinderRot[6];

    obbRot[0][2] = (float)cData.mCylinderRot[8];
    obbRot[1][2] = (float)cData.mCylinderRot[9];
    obbRot[2][2] = (float)cData.mCylinderRot[10];

    OBB obbCapsule(cCenter,cExtents,obbRot);

    Matrix4x4 CapsuleMatrix;
    MakeMatrix(cData.vCylinderPos, cData.mCylinderRot, CapsuleMatrix);

    Matrix4x4 MeshMatrix;
    MakeMatrix(cData.vTrimeshPos, cData.mTrimeshRot, MeshMatrix);

    // TC results
    if (cData.gTrimesh->doBoxTC)
    {
        dxTriMesh::BoxTC* BoxTC = 0;
        for (int i = 0; i < cData.gTrimesh->BoxTCCache.size(); i++)
        {
            if (cData.gTrimesh->BoxTCCache[i].Geom == cData.gCylinder)
            {
                BoxTC = &cData.gTrimesh->BoxTCCache[i];
                break;
            }
        }
        if (!BoxTC)
        {
            cData.gTrimesh->BoxTCCache.push(dxTriMesh::BoxTC());

            BoxTC = &cData.gTrimesh->BoxTCCache[cData.gTrimesh->BoxTCCache.size() - 1];
            BoxTC->Geom = cData.gCylinder;
            BoxTC->FatCoeff = REAL(1.0);
        }

        // Intersect
        Collider.SetTemporalCoherence(true);
        Collider.Collide(*BoxTC, obbCapsule, cData.gTrimesh->Data->BVTree, null, &MeshMatrix);
    }
    else
    {
        Collider.SetTemporalCoherence(false);
        Collider.Collide(dxTriMesh::defaultBoxCache, obbCapsule, cData.gTrimesh->Data->BVTree, null,&MeshMatrix);
    }

    // Retrieve data
    int TriCount = Collider.GetNbTouchedPrimitives();
    const int* Triangles = (const int*)Collider.GetTouchedPrimitives();


    if (TriCount != 0)
    {
        if (cData.gTrimesh->ArrayCallback != null)
        {
            cData.gTrimesh->ArrayCallback(cData.gTrimesh, cData.gCylinder, Triangles, TriCount);
        }

        // allocate buffer for local contacts on stack
        cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK));

        int ctContacts0 = 0;

        // loop through all intersecting triangles
        for (int i = 0; i < TriCount; i++)
        {
            const int Triint = Triangles[i];
            if (!Callback(cData.gTrimesh, cData.gCylinder, Triint)) continue;


            dVector3 dv[3];
            FetchTriangle(cData.gTrimesh, Triint, cData.vTrimeshPos, cData.mTrimeshRot, dv);

            // test this triangle
            TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false);

            // fill-in tri index for generated contacts
            for (; ctContacts0<cData.nContacts; ctContacts0++)
                cData.gLocalContacts[ctContacts0].triIndex = Triint;

            // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue"
            if(cData.nContacts	>= (cData.iFlags & NUMC_MASK))
            {
                break;
            }
        }
    }

    return _ProcessLocalContacts(cData);
}
// capsule - trimesh by CroTeam
// Ported by Nguyem Binh
int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip)
{
    dIASSERT (skip >= (int)sizeof(dContactGeom));
    dIASSERT (o1->type == dTriMeshClass);
    dIASSERT (o2->type == dCapsuleClass);
    dIASSERT ((flags & NUMC_MASK) >= 1);

    int nContactCount = 0;

    dxTriMesh *TriMesh = (dxTriMesh*)o1;
    dxGeom *Capsule = o2;

    sTrimeshCapsuleColliderData cData;
    cData.SetupInitialContext(TriMesh, Capsule, flags, skip);

    const unsigned uiTLSKind = TriMesh->getParentSpaceTLSKind();
    dIASSERT(uiTLSKind == Capsule->getParentSpaceTLSKind()); // The colliding spaces must use matching cleanup method
    TrimeshCollidersCache *pccColliderCache = GetTrimeshCollidersCache(uiTLSKind);
    OBBCollider& Collider = pccColliderCache->_OBBCollider;

    // Will it better to use LSS here? -> confirm Pierre.
    dQueryCCTLPotentialCollisionTriangles(Collider, cData, 
        TriMesh, Capsule, pccColliderCache->defaultBoxCache);

    if (Collider.GetContactStatus()) 
    {
        // Retrieve data
        int TriCount = Collider.GetNbTouchedPrimitives();

        if (TriCount != 0)
        {
            const int* Triangles = (const int*)Collider.GetTouchedPrimitives();

            if (TriMesh->ArrayCallback != null)
            {
                TriMesh->ArrayCallback(TriMesh, Capsule, Triangles, TriCount);
            }

            // allocate buffer for local contacts on stack
            cData.m_gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.m_iFlags & NUMC_MASK));

            unsigned int ctContacts0 = cData.m_ctContacts;

            uint8* UseFlags = TriMesh->Data->UseFlags;

            // loop through all intersecting triangles
            for (int i = 0; i < TriCount; i++)
            {
                const int Triint = Triangles[i];
                if (!Callback(TriMesh, Capsule, Triint)) continue;

                dVector3 dv[3];
                FetchTriangle(TriMesh, Triint, cData.m_mTriMeshPos, cData.m_mTriMeshRot, dv);

                uint8 flags = UseFlags ? UseFlags[Triint] : (uint8)dxTriMeshData::kUseAll;

                bool bFinishSearching;
                ctContacts0 = cData.TestCollisionForSingleTriangle(ctContacts0, Triint, dv, flags, bFinishSearching);

                if (bFinishSearching) 
                {
                    break;
                }
            }

            if (cData.m_ctContacts != 0)
            {
                nContactCount = cData._ProcessLocalContacts(contact, TriMesh, Capsule);
            }
        }
    }

    return nContactCount;
}