Esempio n. 1
0
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //  no lock here!  It's invoked from within Simulate(), which is thread-locked

            if (m_global_contactcount >= maxContactsbeforedeath)
                return;

            // Test if we're colliding a geom with a space.
            // If so we have to drill down into the space recursively


            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                return;

            if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
            {
                // We'll be calling near recursivly if one
                // of them is a space to find all of the
                // contact points in the space
                try
                {
                    d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
                }
                catch (AccessViolationException)
                {
                    m_log.Warn("[PHYSICS]: Unable to collide test a space");
                    return;
                }
                //here one should check collisions of geoms inside a space
                // but on each space we only should have geoms that not colide amoung each other
                // so we don't dig inside spaces
                return;
            }

            // get geom bodies to check if we already a joint contact
            // guess this shouldn't happen now
            IntPtr b1 = d.GeomGetBody(g1);
            IntPtr b2 = d.GeomGetBody(g2);

            // d.GeomClassID id = d.GeomGetClass(g1);

            // Figure out how many contact points we have
            int count = 0;
            try
            {
                // Colliding Geom To Geom
                // This portion of the function 'was' blatantly ripped off from BoxStack.cs

                if (g1 == g2)
                    return; // Can't collide with yourself

                if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
                    return;

                count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
//                ode.drelease(world);
                base.TriggerPhysicsBasedRestart();
            }
            catch (Exception e)
            {
                m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
                return;
            }

            // no contacts so done
            if (count == 0)
                return;

            // now we have a contact describing colision of 2 things
            // but with my changes now we don't know what they are
            // so code gets more complex now

            // try get physical actors 
            PhysicsActor p1;
            PhysicsActor p2;

            if (!actor_name_map.TryGetValue(g1, out p1))
            {
                p1 = PANull;
            }

            if (!actor_name_map.TryGetValue(g2, out p2))
            {
                p2 = PANull;
            }

            // update actors collision score
            if (p1.CollisionScore >= float.MaxValue - count)
                p1.CollisionScore = 0;
            p1.CollisionScore += count;

            if (p2.CollisionScore >= float.MaxValue - count)
                p2.CollisionScore = 0;
            p2.CollisionScore += count;

            // get geoms names
            String name1 = null;
            String name2 = null;

            if (!geom_name_map.TryGetValue(g1, out name1))
            {
                name1 = "null";
            }
            if (!geom_name_map.TryGetValue(g2, out name2))
            {
                name2 = "null";
            }

            ContactPoint maxDepthContact = new ContactPoint();
            d.ContactGeom curContact = new d.ContactGeom();

            float mu;
            float bounce;
            ContactData contactdata1;
            ContactData contactdata2;

            for (int i = 0; i < count; i++)
            {
                if (!GetCurContactGeom(i, ref curContact))
                    break;

                if (curContact.depth <= 0)
                    continue;

                if(curContact.g1 == IntPtr.Zero)
                    curContact.g1 = g1;
                if(curContact.g2 == IntPtr.Zero)
                    curContact.g2 = g2;

//for debug                d.Quaternion qtmp = d.BodyGetQuaternion(b1);

                if (curContact.depth > maxDepthContact.PenetrationDepth)
                {
                    maxDepthContact = new ContactPoint(
                        new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
                        new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
                        curContact.depth
                        );
                }

                IntPtr Joint;

                // inform actors about colision

                if (p1 is OdeCharacter && p2.PhysicsActorType == (int)ActorTypes.Prim)
                    {
                        // Testing if the collision is at the feet of the avatar
                        if ((p1.Position.Z - curContact.pos.Z) > (p1.Size.Z - avCapRadius) * 0.5f)
                            p1.IsColliding = true;
                    }
                else
                {
                    p1.IsColliding = true;
                }

                switch (p2.PhysicsActorType)
                {
                    case (int)ActorTypes.Agent:
                        p1.CollidingObj = true;
                        break;
                    case (int)ActorTypes.Prim:
                        if (p1.Velocity.LengthSquared() > 0.0f)
                            p1.CollidingObj = true;
                        break;
                    case (int)ActorTypes.Unknown:
                        p1.CollidingGround = true;
                        break;
                    default:
                        p1.CollidingGround = true;
                        break;
                }

                if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
                    {
                        // Testing if the collision is at the feet of the avatar
                        if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z - avCapRadius) * 0.5f)
                            p2.IsColliding = true;
                    }
                else
                {
                    p2.IsColliding = true;
                }

                switch (p1.PhysicsActorType)
                {
                    case (int)ActorTypes.Agent:
                        p2.CollidingObj = true;
                        break;
                    case (int)ActorTypes.Prim:
                        if (p2.Velocity.LengthSquared() > 0.0f)
                            p2.CollidingObj = true;
                        break;
                    case (int)ActorTypes.Unknown:
                        p2.CollidingGround = true;
                        break;
                    default:
                        p2.CollidingGround = true;
                        break;
                }

                if (m_global_contactcount >= maxContactsbeforedeath)
                    break;

                // we don't want prim or avatar to explode
                // not in use section, so removed  see older commits if needed

                // skip actors with volumeDetect
                Boolean skipThisContact = false;

                if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
                    skipThisContact = true;   // No collision on volume detect prims

                if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
                    skipThisContact = true;   // No collision on volume detect prims

//                if (!skipThisContact && curContact.depth < 0f)
//                    skipThisContact = true;

                //                if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
                //                    skipThisContact = true;

                Joint = IntPtr.Zero;
                if (!skipThisContact)
                {
                   
                    // If we're colliding against terrain
                    if (name1 == "Terrain")
                    {
                        // avatar to ground
                        /*  not done by ode
                        if (p2.PhysicsActorType == (int)ActorTypes.Agent)
                            {
                            // If we're moving
                            if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
                                {
                                float mu = AvatarMovementTerrainContactSurf.mu;
                                float bounce = AvatarMovementTerrainContactSurf.bounce;
                                float soft_cfm = AvatarMovementTerrainContactSurf.soft_cfm;
                                float soft_erp = AvatarMovementTerrainContactSurf.soft_erp;
                                doJoint = SetGlobalContact(ref curContact, mu, bounce, soft_cfm, soft_erp);
                                }
                            else
                                {
                                // Use the non moving terrain contact
                                float mu = TerrainContactSurf.mu;
                                float bounce = TerrainContactSurf.bounce;
                                float soft_cfm = TerrainContactSurf.soft_cfm;
                                float soft_erp = TerrainContactSurf.soft_erp;
                                doJoint = SetGlobalContact(ref curContact, mu, bounce, soft_cfm, soft_erp);
                                }
                            }
                        else
                            */
                        if (p2.PhysicsActorType == (int)ActorTypes.Prim)
                        {
                            // prim terrain contact

                            contactdata2 = p2.ContactData;

                            bounce = contactdata2.bounce * TerrainBounce;

                            mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction);

                            if (Math.Abs(p2.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y) > 0.1f)
                                mu *= frictionMovementMult;

                            Joint = CreateContacJoint(ref curContact, mu, bounce, true);
                        }
                    }

                    else if (name2 == "Terrain")
                    {
                        // avatar to ground
                        /*  not done by ode
                        if (p1.PhysicsActorType == (int)ActorTypes.Agent)
                            {
                            // If we're moving
                            if (Math.Abs(p1.Velocity.X) > 0.01f || Math.Abs(p1.Velocity.Y) > 0.01f)
                                {
                                // Use the movement terrain contact
                                float mu = AvatarMovementTerrainContactSurf.mu;
                                float bounce = AvatarMovementTerrainContactSurf.bounce;
                                float soft_cfm = AvatarMovementTerrainContactSurf.soft_cfm;
                                float soft_erp = AvatarMovementTerrainContactSurf.soft_erp;
                                doJoint = SetGlobalContact(ref curContact, mu, bounce, soft_cfm, soft_erp);
                                }
                            else
                                {
                                // Use the non moving terrain contact
                                float mu = TerrainContactSurf.mu;
                                float bounce = TerrainContactSurf.bounce;
                                float soft_cfm = TerrainContactSurf.soft_cfm;
                                float soft_erp = TerrainContactSurf.soft_erp;
                                doJoint = SetGlobalContact(ref curContact, mu, bounce, soft_cfm, soft_erp);
                                }
                            }
                        else
                            */
                        if (p1.PhysicsActorType == (int)ActorTypes.Prim)
                        {
                            // prim terrain contact

                            contactdata1 = p1.ContactData;

                            bounce = contactdata1.bounce * TerrainBounce;

                            mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction);

                            if (Math.Abs(p1.Velocity.X) > 0.1f || Math.Abs(p1.Velocity.Y) > 0.1f)
                                mu *= frictionMovementMult;

                            Joint = CreateContacJoint(ref curContact, mu, bounce, true);
                        }
                    }

                    // collisions with water
                    else if (name1 == "Water" || name2 == "Water")
                    {
                        if (curContact.depth > 0.1f)
                        {
                            curContact.depth *= 52;
                            //contact.normal = new d.Vector3(0, 0, 1);
                            //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
                        }
                        mu = 0;
                        bounce = 0;
                        Joint = CreateContacJoint(ref curContact, mu, bounce,true);
                    }

                    else
                    {
                        // we're colliding with prim or avatar
                        if (p1 != null && p2 != null)
                        {
                            contactdata1 = p1.ContactData;
                            contactdata2 = p2.ContactData;

                            bool erpsoft;
                            // avatars fail colisions if 2 soft
                            if (p1.PhysicsActorType == (int)ActorTypes.Agent || p2.PhysicsActorType == (int)ActorTypes.Agent)
                                erpsoft = false;
                            else
                                erpsoft = true;

                            bounce = contactdata1.bounce * contactdata2.bounce;
                            
                            mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);

                            if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f))
                                mu *= frictionMovementMult;

                            Joint = CreateContacJoint(ref curContact, mu, bounce, erpsoft);
                        }
                    }
                    if (Joint != IntPtr.Zero)
                    {
                        m_global_contactcount++;
                        d.JointAttach(Joint, b1, b2);
                    }
                }
            }
            // this was inside above loop ?

            collision_accounting_events(p1, p2, maxDepthContact);

/*
            if (notskipedcount > geomContactPointsStartthrottle)
            {
                // If there are more then 3 contact points, it's likely
                // that we've got a pile of objects, so ...
                // We don't want to send out hundreds of terse updates over and over again
                // so lets throttle them and send them again after it's somewhat sorted out.
                 this needs checking so out for now
                                if (b1 != IntPtr.Zero)
                                    p1.ThrottleUpdates = true;
                                if (b2 != IntPtr.Zero)
                                    p2.ThrottleUpdates = true;
                
            }
 */
        }            
        // This is the standard Near. g2 is the ray
        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //Don't test against heightfield Geom, or you'll be sorry!
            // Exclude heightfield geom

            if (g1 == IntPtr.Zero || g1 == g2)
                return;

            if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
                return;

            // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
            if (d.GeomIsSpace(g1))
            {
                try
                {
                    d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
                }
                catch (Exception e)
                {
                    m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
                }
                return;
            }

            int count = 0;
            try
            {
                count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                m_log.Error("[PHYSICS Ray]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
            }
            catch (Exception e)
            {
                m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
                return;
            }

            if (count == 0)
                return;

            PhysicsActor p1 = null;

            if (g1 != IntPtr.Zero)
                m_scene.actor_name_map.TryGetValue(g1, out p1);

            d.ContactGeom curcontact = new d.ContactGeom();
            // Loop over contacts, build results.
            for (int i = 0; i < count; i++)
            {
                if (!GetCurContactGeom(i, ref curcontact))
                    break;
                if (p1 != null) { 
                    if (p1 is OdePrim)
                    {
                        ContactResult collisionresult = new ContactResult();
                    
                        collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
                        collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z);
                        collisionresult.Depth = curcontact.depth;
                        collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y,
                                                             curcontact.normal.Z);
                        lock (m_contactResults)
                            m_contactResults.Add(collisionresult);
                    }
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// This is our near callback.  A geometry is near a body
        /// </summary>
        /// <param name="space">The space that contains the geoms.  Remember, spaces are also geoms</param>
        /// <param name="g1">a geometry or space</param>
        /// <param name="g2">another geometry or space</param>
        /// 

        private void near(IntPtr space, IntPtr g1, IntPtr g2)
        {
            //  no lock here!  It's invoked from within Simulate(), which is thread-locked

            if (m_global_contactcount >= maxContactsbeforedeath)
                return;

            // Test if we're colliding a geom with a space.
            // If so we have to drill down into the space recursively

            if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
                return;

            if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
            {
                // We'll be calling near recursivly if one
                // of them is a space to find all of the
                // contact points in the space
                try
                {
                    d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
                }
                catch (AccessViolationException)
                {
                    m_log.Warn("[PHYSICS]: Unable to collide test a space");
                    return;
                }
                //here one should check collisions of geoms inside a space
                // but on each space we only should have geoms that not colide amoung each other
                // so we don't dig inside spaces
                return;
            }

            // get geom bodies to check if we already a joint contact
            // guess this shouldn't happen now
            IntPtr b1 = d.GeomGetBody(g1);
            IntPtr b2 = d.GeomGetBody(g2);

            // d.GeomClassID id = d.GeomGetClass(g1);

            // Figure out how many contact points we have
            int count = 0;
            try
            {
                // Colliding Geom To Geom
                // This portion of the function 'was' blatantly ripped off from BoxStack.cs

                if (g1 == g2)
                    return; // Can't collide with yourself

                if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
                    return;
                /*
                // debug
                                PhysicsActor dp2;
                                if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
                                {
                                    d.AABB aabb;
                                    d.GeomGetAABB(g2, out aabb);
                                    float x = aabb.MaxX - aabb.MinX;
                                    float y = aabb.MaxY - aabb.MinY;
                                    float z = aabb.MaxZ - aabb.MinZ;
                                    if (x > 60.0f || y > 60.0f || z > 60.0f)
                                    {
                                        if (!actor_name_map.TryGetValue(g2, out dp2))
                                            m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
                                        else
                                            m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})",
                                                dp2.Name, dp2.Size, x, y, z,
                                                dp2.Position.ToString(),
                                                dp2.Orientation.ToString(),
                                                dp2.Orientation.Length());
                                        return;
                                    }
                                }
                //
                */


                if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc ||
                    d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc)
                {
                    int cflags;
                    unchecked
                    {
                        cflags = (int)(1 | d.CONTACTS_UNIMPORTANT);
                    }
                    count = d.CollidePtr(g1, g2, cflags, ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
                }
                else
                    count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
            }
            catch (SEHException)
            {
                m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory.  This could be a result of really irregular terrain.  If this repeats continuously, restart using Basic Physics and terrain fill your terrain.  Restarting the sim.");
                //                ode.drelease(world);
                base.TriggerPhysicsBasedRestart();
            }
            catch (Exception e)
            {
                m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
                return;
            }

            // contacts done
            if (count == 0)
                return;

            // try get physical actors 
            PhysicsActor p1;
            PhysicsActor p2;

            if (!actor_name_map.TryGetValue(g1, out p1))
            {
                m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1");
                return;
            }

            if (!actor_name_map.TryGetValue(g2, out p2))
            {
                m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2");
                return;
            }

            // update actors collision score
            if (p1.CollisionScore >= float.MaxValue - count)
                p1.CollisionScore = 0;
            p1.CollisionScore += count;

            if (p2.CollisionScore >= float.MaxValue - count)
                p2.CollisionScore = 0;
            p2.CollisionScore += count;

            // get first contact
            d.ContactGeom curContact = new d.ContactGeom();

            if (!GetCurContactGeom(0, ref curContact))
                return;

            ContactPoint maxDepthContact = new ContactPoint();

            // do volume detection case
            if ((p1.IsVolumeDtc || p2.IsVolumeDtc))
            {
                maxDepthContact = new ContactPoint(
                    new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
                    new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
                    curContact.depth, false
                    );

                collision_accounting_events(p1, p2, maxDepthContact);
                return;
            }

            // big messy collision analises

            float mu = 0;
            float bounce = 0;
//            bool IgnoreNegSides = false;

            ContactData contactdata1 = new ContactData(0, 0, false);
            ContactData contactdata2 = new ContactData(0, 0, false);

            bool dop1ava = false;
            bool dop2ava = false;
            bool ignore = false;
            bool smoothMesh = false;

            switch (p1.PhysicsActorType)
            {
                case (int)ActorTypes.Agent:
                    {
                        dop1ava = true;
                        switch (p2.PhysicsActorType)
                        {
                            case (int)ActorTypes.Agent:
                            case (int)ActorTypes.Prim:
                                break;

                            default:
                                ignore = true; // avatar to terrain and water ignored
                                break;
                        }
                        break;
                    }

                case (int)ActorTypes.Prim:
                    {
                        switch (p2.PhysicsActorType)
                        {
                            case (int)ActorTypes.Agent:
                                dop2ava = true;
                                break;

                            case (int)ActorTypes.Prim:
                                Vector3 relV = p1.rootVelocity - p2.rootVelocity;
                                float relVlenSQ = relV.LengthSquared();
                                if (relVlenSQ > 0.0001f)
                                {
                                    p1.CollidingObj = true;
                                    p2.CollidingObj = true;
                                }
                                p1.getContactData(ref contactdata1);
                                p2.getContactData(ref contactdata2);
                                bounce = contactdata1.bounce * contactdata2.bounce;
                                mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu);

                                if (relVlenSQ > 0.01f)
                                    mu *= frictionMovementMult;

                                if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass &&
                                    d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
                                    smoothMesh = true;
                                break;

                            case (int)ActorTypes.Ground:
                                p1.getContactData(ref contactdata1);
                                bounce = contactdata1.bounce * TerrainBounce;
                                mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction);

                                Vector3 v1 = p1.rootVelocity;
                                if (Math.Abs(v1.X) > 0.1f || Math.Abs(v1.Y) > 0.1f)
                                    mu *= frictionMovementMult;
                                p1.CollidingGround = true;

                                if(d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
                                    smoothMesh = true;
                                break;

                            case (int)ActorTypes.Water:
                            default:
                                ignore = true;
                                break;
                        }
                    }
                    break;

                case (int)ActorTypes.Ground:
                    if (p2.PhysicsActorType == (int)ActorTypes.Prim)
                    {
                        p2.CollidingGround = true;
                        p2.getContactData(ref contactdata2);
                        bounce = contactdata2.bounce * TerrainBounce;
                        mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction);

//                        if (curContact.side1 > 0) // should be 2 ?
//                            IgnoreNegSides = true;
                        Vector3 v2 = p2.rootVelocity;
                        if (Math.Abs(v2.X) > 0.1f || Math.Abs(v2.Y) > 0.1f)
                            mu *= frictionMovementMult;

                        if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass)
                            smoothMesh = true;
                    }
                    else
                        ignore = true;
                    break;

                case (int)ActorTypes.Water:
                default:
                    break;
            }

            if (ignore)
                return;

            IntPtr Joint;
            bool FeetCollision = false;
            int ncontacts = 0;

            int i = 0;

            maxDepthContact = new ContactPoint();
            maxDepthContact.PenetrationDepth = float.MinValue;
            ContactPoint minDepthContact = new ContactPoint();
            minDepthContact.PenetrationDepth = float.MaxValue;

            SharedTmpcontact.geom.depth = 0;
            SharedTmpcontact.surface.mu = mu;
            SharedTmpcontact.surface.bounce = bounce;

            d.ContactGeom altContact = new d.ContactGeom();
            bool useAltcontact = false;
            bool noskip = true;

            if(dop1ava || dop2ava)
                smoothMesh = false;

            while (true)
            {
                noskip = true;
                useAltcontact = false;

                if (dop1ava)
                {
                    if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
                    {
                        if (p2.PhysicsActorType == (int)ActorTypes.Agent)
                        {
                            p1.CollidingObj = true;
                            p2.CollidingObj = true;
                        }
                        else if (p2.rootVelocity.LengthSquared() > 0.0f)
                            p2.CollidingObj = true;
                    }
                    else
                        noskip = false;
                }
                else if (dop2ava)
                {
                if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
                    {
                    if (p1.PhysicsActorType == (int)ActorTypes.Agent)
                        {
                            p1.CollidingObj = true;
                            p2.CollidingObj = true;
                        }
                    else if (p1.rootVelocity.LengthSquared() > 0.0f)
                        p1.CollidingObj = true;
                    }
                else
                    noskip = false;
                }

                if (noskip)
                {
                    if(useAltcontact)
                        Joint = CreateContacJoint(ref altContact,smoothMesh);
                    else
                        Joint = CreateContacJoint(ref curContact,smoothMesh);

                    if (Joint == IntPtr.Zero)
                        break;

                    d.JointAttach(Joint, b1, b2);

                    ncontacts++;

                    if (curContact.depth > maxDepthContact.PenetrationDepth)
                    {
                        maxDepthContact.Position.X = curContact.pos.X;
                        maxDepthContact.Position.Y = curContact.pos.Y;
                        maxDepthContact.Position.Z = curContact.pos.Z;
                        maxDepthContact.PenetrationDepth = curContact.depth;
                        maxDepthContact.CharacterFeet = FeetCollision;
                    }

                    if (curContact.depth < minDepthContact.PenetrationDepth)
                    {
                        minDepthContact.PenetrationDepth = curContact.depth;
                        minDepthContact.SurfaceNormal.X = curContact.normal.X;
                        minDepthContact.SurfaceNormal.Y = curContact.normal.Y;
                        minDepthContact.SurfaceNormal.Z = curContact.normal.Z;
                    }
                }

                if (++i >= count)
                    break;

                if (!GetCurContactGeom(i, ref curContact))
                    break;
            }

            if (ncontacts > 0)
            {
                maxDepthContact.SurfaceNormal.X = minDepthContact.SurfaceNormal.X;
                maxDepthContact.SurfaceNormal.Y = minDepthContact.SurfaceNormal.Y;
                maxDepthContact.SurfaceNormal.Z = minDepthContact.SurfaceNormal.Z;

                collision_accounting_events(p1, p2, maxDepthContact);
            }
        }