Package com.bulletphysics.dynamics

Source Code of com.bulletphysics.dynamics.DiscreteDynamicsWorld$InplaceSolverIslandCallback

/*
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*    claim that you wrote the original software. If you use this software
*    in a product, an acknowledgment in the product documentation would be
*    appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

package com.bulletphysics.dynamics;

import com.bulletphysics.collision.dispatch.CollisionWorld.LocalConvexResult;
import java.util.Comparator;
import com.bulletphysics.BulletGlobals;
import com.bulletphysics.BulletStats;
import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.BroadphasePair;
import com.bulletphysics.collision.broadphase.BroadphaseProxy;
import com.bulletphysics.collision.broadphase.CollisionFilterGroups;
import com.bulletphysics.collision.broadphase.Dispatcher;
import com.bulletphysics.collision.broadphase.DispatcherInfo;
import com.bulletphysics.collision.broadphase.OverlappingPairCache;
import com.bulletphysics.collision.dispatch.CollisionConfiguration;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.CollisionWorld;
import com.bulletphysics.collision.dispatch.CollisionWorld.ClosestConvexResultCallback;
import com.bulletphysics.collision.dispatch.SimulationIslandManager;
import com.bulletphysics.collision.narrowphase.ManifoldPoint;
import com.bulletphysics.collision.narrowphase.PersistentManifold;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.InternalTriangleIndexCallback;
import com.bulletphysics.collision.shapes.SphereShape;
import com.bulletphysics.collision.shapes.TriangleCallback;
import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.ContactSolverInfo;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.TypedConstraint;
import com.bulletphysics.dynamics.vehicle.RaycastVehicle;
import com.bulletphysics.linearmath.CProfileManager;
import com.bulletphysics.linearmath.DebugDrawModes;
import com.bulletphysics.linearmath.IDebugDraw;
import com.bulletphysics.linearmath.MiscUtil;
import com.bulletphysics.linearmath.ScalarUtil;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.TransformUtil;
import com.bulletphysics.util.ObjectArrayList;
import cz.advel.stack.Stack;
import javax.vecmath.Vector3f;

/**
* DiscreteDynamicsWorld provides discrete rigid body simulation.
*
* @author jezek2
*/
public class DiscreteDynamicsWorld extends DynamicsWorld {

  protected ConstraintSolver constraintSolver;
  protected SimulationIslandManager islandManager;
  protected final ObjectArrayList<TypedConstraint> constraints = new ObjectArrayList<TypedConstraint>();
  protected final Vector3f gravity = new Vector3f(0f, -10f, 0f);

  //for variable timesteps
  protected float localTime = 1f / 60f;
  //for variable timesteps

  protected boolean ownsIslandManager;
  protected boolean ownsConstraintSolver;

  protected ObjectArrayList<RaycastVehicle> vehicles = new ObjectArrayList<RaycastVehicle>();
 
  protected ObjectArrayList<ActionInterface> actions = new ObjectArrayList<ActionInterface>();

  protected int profileTimings = 0;

        protected InternalTickCallback preTickCallback;
 
  public DiscreteDynamicsWorld(Dispatcher dispatcher, BroadphaseInterface pairCache, ConstraintSolver constraintSolver, CollisionConfiguration collisionConfiguration) {
    super(dispatcher, pairCache, collisionConfiguration);
    this.constraintSolver = constraintSolver;

    if (this.constraintSolver == null) {
      this.constraintSolver = new SequentialImpulseConstraintSolver();
      ownsConstraintSolver = true;
    }
    else {
      ownsConstraintSolver = false;
    }

    {
      islandManager = new SimulationIslandManager();
    }

    ownsIslandManager = true;
  }

  protected void saveKinematicState(float timeStep) {
    for (int i = 0; i < collisionObjects.size(); i++) {
      CollisionObject colObj = collisionObjects.getQuick(i);
      RigidBody body = RigidBody.upcast(colObj);
      if (body != null) {
        //Transform predictedTrans = new Transform();
        if (body.getActivationState() != CollisionObject.ISLAND_SLEEPING) {
          if (body.isKinematicObject()) {
            // to calculate velocities next frame
            body.saveKinematicState(timeStep);
          }
        }
      }
    }
  }

  @Override
  public void debugDrawWorld() {
    if (getDebugDrawer() != null && (getDebugDrawer().getDebugMode() & DebugDrawModes.DRAW_CONTACT_POINTS) != 0) {
      int numManifolds = getDispatcher().getNumManifolds();
      Vector3f color = Stack.alloc(Vector3f.class);
      color.set(0f, 0f, 0f);
      for (int i = 0; i < numManifolds; i++) {
        PersistentManifold contactManifold = getDispatcher().getManifoldByIndexInternal(i);
        //btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
        //btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());

        int numContacts = contactManifold.getNumContacts();
        for (int j = 0; j < numContacts; j++) {
          ManifoldPoint cp = contactManifold.getContactPoint(j);
          getDebugDrawer().drawContactPoint(cp.positionWorldOnB, cp.normalWorldOnB, cp.getDistance(), cp.getLifeTime(), color);
        }
      }
    }
   
    if (getDebugDrawer() != null && (getDebugDrawer().getDebugMode() & (DebugDrawModes.DRAW_WIREFRAME | DebugDrawModes.DRAW_AABB)) != 0) {
      int i;

      Transform tmpTrans = Stack.alloc(Transform.class);
      Vector3f minAabb = Stack.alloc(Vector3f.class);
      Vector3f maxAabb = Stack.alloc(Vector3f.class);
      Vector3f colorvec = Stack.alloc(Vector3f.class);
     
      // todo: iterate over awake simulation islands!
      for (i = 0; i < collisionObjects.size(); i++) {
        CollisionObject colObj = collisionObjects.getQuick(i);
        if (getDebugDrawer() != null && (getDebugDrawer().getDebugMode() & DebugDrawModes.DRAW_WIREFRAME) != 0) {
          Vector3f color = Stack.alloc(Vector3f.class);
          color.set(255f, 255f, 255f);
          switch (colObj.getActivationState()) {
            case CollisionObject.ACTIVE_TAG:
              color.set(255f, 255f, 255f);
              break;
            case CollisionObject.ISLAND_SLEEPING:
              color.set(0f, 255f, 0f);
              break;
            case CollisionObject.WANTS_DEACTIVATION:
              color.set(0f, 255f, 255f);
              break;
            case CollisionObject.DISABLE_DEACTIVATION:
              color.set(255f, 0f, 0f);
              break;
            case CollisionObject.DISABLE_SIMULATION:
              color.set(255f, 255f, 0f);
              break;
            default: {
              color.set(255f, 0f, 0f);
            }
          }

          debugDrawObject(colObj.getWorldTransform(tmpTrans), colObj.getCollisionShape(), color);
        }
        if (debugDrawer != null && (debugDrawer.getDebugMode() & DebugDrawModes.DRAW_AABB) != 0) {
          colorvec.set(1f, 0f, 0f);
          colObj.getCollisionShape().getAabb(colObj.getWorldTransform(tmpTrans), minAabb, maxAabb);
          debugDrawer.drawAabb(minAabb, maxAabb, colorvec);
        }
      }

      Vector3f wheelColor = Stack.alloc(Vector3f.class);
      Vector3f wheelPosWS = Stack.alloc(Vector3f.class);
      Vector3f axle = Stack.alloc(Vector3f.class);
      Vector3f tmp = Stack.alloc(Vector3f.class);

      for (i = 0; i < vehicles.size(); i++) {
        for (int v = 0; v < vehicles.getQuick(i).getNumWheels(); v++) {
          wheelColor.set(0, 255, 255);
          if (vehicles.getQuick(i).getWheelInfo(v).raycastInfo.isInContact) {
            wheelColor.set(0, 0, 255);
          }
          else {
            wheelColor.set(255, 0, 255);
          }

          wheelPosWS.set(vehicles.getQuick(i).getWheelInfo(v).worldTransform.origin);

          axle.set(
              vehicles.getQuick(i).getWheelInfo(v).worldTransform.basis.getElement(0, vehicles.getQuick(i).getRightAxis()),
              vehicles.getQuick(i).getWheelInfo(v).worldTransform.basis.getElement(1, vehicles.getQuick(i).getRightAxis()),
              vehicles.getQuick(i).getWheelInfo(v).worldTransform.basis.getElement(2, vehicles.getQuick(i).getRightAxis()));


          //m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_wheelAxleWS
          //debug wheels (cylinders)
          tmp.add(wheelPosWS, axle);
          debugDrawer.drawLine(wheelPosWS, tmp, wheelColor);
          debugDrawer.drawLine(wheelPosWS, vehicles.getQuick(i).getWheelInfo(v).raycastInfo.contactPointWS, wheelColor);
        }
      }

      if (getDebugDrawer() != null && getDebugDrawer().getDebugMode() != 0) {
        for (i=0; i<actions.size(); i++) {
          actions.getQuick(i).debugDraw(debugDrawer);
        }
      }
    }
  }

  @Override
  public void clearForces() {
    // todo: iterate over awake simulation islands!
    for (int i = 0; i < collisionObjects.size(); i++) {
      CollisionObject colObj = collisionObjects.getQuick(i);

      RigidBody body = RigidBody.upcast(colObj);
      if (body != null) {
        body.clearForces();
      }
    }
  }
 
  /**
   * Apply gravity, call this once per timestep.
   */
  public void applyGravity() {
    // todo: iterate over awake simulation islands!
    for (int i = 0; i < collisionObjects.size(); i++) {
      CollisionObject colObj = collisionObjects.getQuick(i);

      RigidBody body = RigidBody.upcast(colObj);
      if (body != null && body.isActive()) {
        body.applyGravity();
      }
    }
  }

  protected void synchronizeMotionStates() {
    Transform interpolatedTransform = Stack.alloc(Transform.class);
   
    Transform tmpTrans = Stack.alloc(Transform.class);
    Vector3f tmpLinVel = Stack.alloc(Vector3f.class);
    Vector3f tmpAngVel = Stack.alloc(Vector3f.class);

    // todo: iterate over awake simulation islands!
    for (int i = 0; i < collisionObjects.size(); i++) {
      CollisionObject colObj = collisionObjects.getQuick(i);

      RigidBody body = RigidBody.upcast(colObj);
      if (body != null && body.getMotionState() != null && !body.isStaticOrKinematicObject()) {
        // we need to call the update at least once, even for sleeping objects
        // otherwise the 'graphics' transform never updates properly
        // so todo: add 'dirty' flag
        //if (body->getActivationState() != ISLAND_SLEEPING)
        {
          TransformUtil.integrateTransform(
              body.getInterpolationWorldTransform(tmpTrans),
              body.getInterpolationLinearVelocity(tmpLinVel),
              body.getInterpolationAngularVelocity(tmpAngVel),
              localTime * body.getHitFraction(), interpolatedTransform);
          body.getMotionState().setWorldTransform(interpolatedTransform);
        }
      }
    }

    if (getDebugDrawer() != null && (getDebugDrawer().getDebugMode() & DebugDrawModes.DRAW_WIREFRAME) != 0) {
      for (int i = 0; i < vehicles.size(); i++) {
        for (int v = 0; v < vehicles.getQuick(i).getNumWheels(); v++) {
          // synchronize the wheels with the (interpolated) chassis worldtransform
          vehicles.getQuick(i).updateWheelTransform(v, true);
        }
      }
    }
  }

  @Override
  public int stepSimulation(float timeStep, int maxSubSteps, float fixedTimeStep) {
    startProfiling(timeStep);

    long t0 = System.nanoTime();
   
    BulletStats.pushProfile("stepSimulation");
    try {
      int numSimulationSubSteps = 0;

      if (maxSubSteps != 0) {
        // fixed timestep with interpolation
        localTime += timeStep;
        if (localTime >= fixedTimeStep) {
          numSimulationSubSteps = (int) (localTime / fixedTimeStep);
          localTime -= numSimulationSubSteps * fixedTimeStep;
        }
      }
      else {
        //variable timestep
        fixedTimeStep = timeStep;
        localTime = timeStep;
        if (ScalarUtil.fuzzyZero(timeStep)) {
          numSimulationSubSteps = 0;
          maxSubSteps = 0;
        }
        else {
          numSimulationSubSteps = 1;
          maxSubSteps = 1;
        }
      }

      // process some debugging flags
      if (getDebugDrawer() != null) {
        BulletGlobals.setDeactivationDisabled((getDebugDrawer().getDebugMode() & DebugDrawModes.NO_DEACTIVATION) != 0);
      }
      if (numSimulationSubSteps != 0) {
        saveKinematicState(fixedTimeStep);

        applyGravity();

        // clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
        int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps) ? maxSubSteps : numSimulationSubSteps;

        for (int i = 0; i < clampedSimulationSteps; i++) {
          internalSingleStepSimulation(fixedTimeStep);
          synchronizeMotionStates();
        }
      }

      synchronizeMotionStates();

      clearForces();

      //#ifndef BT_NO_PROFILE
      CProfileManager.incrementFrameCounter();
      //#endif //BT_NO_PROFILE

      return numSimulationSubSteps;
    }
    finally {
      BulletStats.popProfile();
     
      BulletStats.stepSimulationTime = (System.nanoTime() - t0) / 1000000;
    }
  }

  protected void internalSingleStepSimulation(float timeStep) {
    BulletStats.pushProfile("internalSingleStepSimulation");
    try {
                        if (preTickCallback != null) {
        preTickCallback.internalTick(this, timeStep);
      }

      // apply gravity, predict motion
      predictUnconstraintMotion(timeStep);

      DispatcherInfo dispatchInfo = getDispatchInfo();

      dispatchInfo.timeStep = timeStep;
      dispatchInfo.stepCount = 0;
      dispatchInfo.debugDraw = getDebugDrawer();

      // perform collision detection
      performDiscreteCollisionDetection();

      calculateSimulationIslands();

      getSolverInfo().timeStep = timeStep;

      // solve contact and other joint constraints
      solveConstraints(getSolverInfo());

      //CallbackTriggers();

      // integrate transforms
      integrateTransforms(timeStep);

      // update vehicle simulation
      updateActions(timeStep);

      // update vehicle simulation
      updateVehicles(timeStep);

      updateActivationState(timeStep);

                        if (internalTickCallback != null) {
        internalTickCallback.internalTick(this, timeStep);
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }

  @Override
  public void setGravity(Vector3f gravity) {
    this.gravity.set(gravity);
    for (int i = 0; i < collisionObjects.size(); i++) {
      CollisionObject colObj = collisionObjects.getQuick(i);
      RigidBody body = RigidBody.upcast(colObj);
      if (body != null) {
        body.setGravity(gravity);
      }
    }
  }
 
  @Override
  public Vector3f getGravity(Vector3f out) {
    out.set(gravity);
    return out;
  }

  @Override
  public void removeRigidBody(RigidBody body) {
    removeCollisionObject(body);
  }

  @Override
  public void addRigidBody(RigidBody body) {
    if (!body.isStaticOrKinematicObject()) {
      body.setGravity(gravity);
    }

    if (body.getCollisionShape() != null) {
      boolean isDynamic = !(body.isStaticObject() || body.isKinematicObject());
      short collisionFilterGroup = isDynamic ? (short) CollisionFilterGroups.DEFAULT_FILTER : (short) CollisionFilterGroups.STATIC_FILTER;
      short collisionFilterMask = isDynamic ? (short) CollisionFilterGroups.ALL_FILTER : (short) (CollisionFilterGroups.ALL_FILTER ^ CollisionFilterGroups.STATIC_FILTER);

      addCollisionObject(body, collisionFilterGroup, collisionFilterMask);
    }
  }

  public void addRigidBody(RigidBody body, short group, short mask) {
    if (!body.isStaticOrKinematicObject()) {
      body.setGravity(gravity);
    }

    if (body.getCollisionShape() != null) {
      addCollisionObject(body, group, mask);
    }
  }

  public void updateActions(float timeStep) {
    BulletStats.pushProfile("updateActions");
    try {
      for (int i=0; i<actions.size(); i++) {
        actions.getQuick(i).updateAction(this, timeStep);
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }

  protected void updateVehicles(float timeStep) {
    BulletStats.pushProfile("updateVehicles");
    try {
      for (int i = 0; i < vehicles.size(); i++) {
        RaycastVehicle vehicle = vehicles.getQuick(i);
        vehicle.updateVehicle(timeStep);
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }

  protected void updateActivationState(float timeStep) {
    BulletStats.pushProfile("updateActivationState");
    try {
      Vector3f tmp = Stack.alloc(Vector3f.class);

      for (int i=0; i<collisionObjects.size(); i++) {
        CollisionObject colObj = collisionObjects.getQuick(i);
        RigidBody body = RigidBody.upcast(colObj);
        if (body != null) {
          body.updateDeactivation(timeStep);

          if (body.wantsSleeping()) {
            if (body.isStaticOrKinematicObject()) {
              body.setActivationState(CollisionObject.ISLAND_SLEEPING);
            }
            else {
              if (body.getActivationState() == CollisionObject.ACTIVE_TAG) {
                body.setActivationState(CollisionObject.WANTS_DEACTIVATION);
              }
              if (body.getActivationState() == CollisionObject.ISLAND_SLEEPING) {
                tmp.set(0f, 0f, 0f);
                body.setAngularVelocity(tmp);
                body.setLinearVelocity(tmp);
              }
            }
          }
          else {
            if (body.getActivationState() != CollisionObject.DISABLE_DEACTIVATION) {
              body.setActivationState(CollisionObject.ACTIVE_TAG);
            }
          }
        }
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }

  @Override
  public void addConstraint(TypedConstraint constraint, boolean disableCollisionsBetweenLinkedBodies) {
    constraints.add(constraint);
    if (disableCollisionsBetweenLinkedBodies) {
      constraint.getRigidBodyA().addConstraintRef(constraint);
      constraint.getRigidBodyB().addConstraintRef(constraint);
    }
  }

  @Override
  public void removeConstraint(TypedConstraint constraint) {
    constraints.remove(constraint);
    constraint.getRigidBodyA().removeConstraintRef(constraint);
    constraint.getRigidBodyB().removeConstraintRef(constraint);
  }

  @Override
  public void addAction(ActionInterface action) {
    actions.add(action);
  }

  @Override
  public void removeAction(ActionInterface action) {
    actions.remove(action);
  }

  @Override
  public void addVehicle(RaycastVehicle vehicle) {
    vehicles.add(vehicle);
  }
 
  @Override
  public void removeVehicle(RaycastVehicle vehicle) {
    vehicles.remove(vehicle);
  }
 
  private static int getConstraintIslandId(TypedConstraint lhs) {
    int islandId;

    CollisionObject rcolObj0 = lhs.getRigidBodyA();
    CollisionObject rcolObj1 = lhs.getRigidBodyB();
    islandId = rcolObj0.getIslandTag() >= 0 ? rcolObj0.getIslandTag() : rcolObj1.getIslandTag();
    return islandId;
  }
 
  private static class InplaceSolverIslandCallback extends SimulationIslandManager.IslandCallback {
    public ContactSolverInfo solverInfo;
    public ConstraintSolver solver;
    public ObjectArrayList<TypedConstraint> sortedConstraints;
    public int numConstraints;
    public IDebugDraw debugDrawer;
    //public StackAlloc* m_stackAlloc;
    public Dispatcher dispatcher;

    public void init(ContactSolverInfo solverInfo, ConstraintSolver solver, ObjectArrayList<TypedConstraint> sortedConstraints, int numConstraints, IDebugDraw debugDrawer, Dispatcher dispatcher) {
      this.solverInfo = solverInfo;
      this.solver = solver;
      this.sortedConstraints = sortedConstraints;
      this.numConstraints = numConstraints;
      this.debugDrawer = debugDrawer;
      this.dispatcher = dispatcher;
    }

    public void processIsland(ObjectArrayList<CollisionObject> bodies, int numBodies, ObjectArrayList<PersistentManifold> manifolds, int manifolds_offset, int numManifolds, int islandId) {
      if (islandId < 0) {
        // we don't split islands, so all constraints/contact manifolds/bodies are passed into the solver regardless the island id
        solver.solveGroup(bodies, numBodies, manifolds, manifolds_offset, numManifolds, sortedConstraints, 0, numConstraints, solverInfo, debugDrawer/*,m_stackAlloc*/, dispatcher);
      }
      else {
        // also add all non-contact constraints/joints for this island
        //ObjectArrayList<TypedConstraint> startConstraint = null;
        int startConstraint_idx = -1;
        int numCurConstraints = 0;
        int i;

        // find the first constraint for this island
        for (i = 0; i < numConstraints; i++) {
          if (getConstraintIslandId(sortedConstraints.getQuick(i)) == islandId) {
            //startConstraint = &m_sortedConstraints[i];
            //startConstraint = sortedConstraints.subList(i, sortedConstraints.size());
            startConstraint_idx = i;
            break;
          }
        }
        // count the number of constraints in this island
        for (; i < numConstraints; i++) {
          if (getConstraintIslandId(sortedConstraints.getQuick(i)) == islandId) {
            numCurConstraints++;
          }
        }

        // only call solveGroup if there is some work: avoid virtual function call, its overhead can be excessive
        if ((numManifolds + numCurConstraints) > 0) {
          solver.solveGroup(bodies, numBodies, manifolds, manifolds_offset, numManifolds, sortedConstraints, startConstraint_idx, numCurConstraints, solverInfo, debugDrawer/*,m_stackAlloc*/, dispatcher);
        }
      }
    }
  }

  private ObjectArrayList<TypedConstraint> sortedConstraints = new ObjectArrayList<TypedConstraint>();
  private InplaceSolverIslandCallback solverCallback = new InplaceSolverIslandCallback();
 
  protected void solveConstraints(ContactSolverInfo solverInfo) {
    BulletStats.pushProfile("solveConstraints");
    try {
      // sorted version of all btTypedConstraint, based on islandId
      sortedConstraints.clear();
      for (int i=0; i<constraints.size(); i++) {
        sortedConstraints.add(constraints.getQuick(i));
      }
      //Collections.sort(sortedConstraints, sortConstraintOnIslandPredicate);
      MiscUtil.quickSort(sortedConstraints, sortConstraintOnIslandPredicate);

      ObjectArrayList<TypedConstraint> constraintsPtr = getNumConstraints() != 0 ? sortedConstraints : null;

      solverCallback.init(solverInfo, constraintSolver, constraintsPtr, sortedConstraints.size(), debugDrawer/*,m_stackAlloc*/, dispatcher1);

      constraintSolver.prepareSolve(getCollisionWorld().getNumCollisionObjects(), getCollisionWorld().getDispatcher().getNumManifolds());

      // solve all the constraints for this island
      islandManager.buildAndProcessIslands(getCollisionWorld().getDispatcher(), getCollisionWorld().getCollisionObjectArray(), solverCallback);

      constraintSolver.allSolved(solverInfo, debugDrawer/*, m_stackAlloc*/);
    }
    finally {
      BulletStats.popProfile();
    }
  }

  protected void calculateSimulationIslands() {
    BulletStats.pushProfile("calculateSimulationIslands");
    try {
      getSimulationIslandManager().updateActivationState(getCollisionWorld(), getCollisionWorld().getDispatcher());

      {
        int i;
        int numConstraints = constraints.size();
        for (i = 0; i < numConstraints; i++) {
          TypedConstraint constraint = constraints.getQuick(i);

          RigidBody colObj0 = constraint.getRigidBodyA();
          RigidBody colObj1 = constraint.getRigidBodyB();

          if (((colObj0 != null) && (!colObj0.isStaticOrKinematicObject())) &&
            ((colObj1 != null) && (!colObj1.isStaticOrKinematicObject())))
          {
            if (colObj0.isActive() || colObj1.isActive()) {
              getSimulationIslandManager().getUnionFind().unite((colObj0).getIslandTag(), (colObj1).getIslandTag());
            }
          }
        }
      }

      // Store the island id in each body
      getSimulationIslandManager().storeIslandActivationState(getCollisionWorld());
    }
    finally {
      BulletStats.popProfile();
    }
  }

  protected void integrateTransforms(float timeStep) {
    BulletStats.pushProfile("integrateTransforms");
    try {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      Transform tmpTrans = Stack.alloc(Transform.class);

      Transform predictedTrans = Stack.alloc(Transform.class);
      for (int i=0; i<collisionObjects.size(); i++) {
        CollisionObject colObj = collisionObjects.getQuick(i);
        RigidBody body = RigidBody.upcast(colObj);
        if (body != null) {
          body.setHitFraction(1f);

          if (body.isActive() && (!body.isStaticOrKinematicObject())) {
            body.predictIntegratedTransform(timeStep, predictedTrans);

            tmp.sub(predictedTrans.origin, body.getWorldTransform(tmpTrans).origin);
            float squareMotion = tmp.lengthSquared();

            if (body.getCcdSquareMotionThreshold() != 0f && body.getCcdSquareMotionThreshold() < squareMotion) {
              BulletStats.pushProfile("CCD motion clamping");
              try {
                if (body.getCollisionShape().isConvex()) {
                  BulletStats.gNumClampedCcdMotions++;

                  ClosestNotMeConvexResultCallback sweepResults = new ClosestNotMeConvexResultCallback(body, body.getWorldTransform(tmpTrans).origin, predictedTrans.origin, getBroadphase().getOverlappingPairCache(), getDispatcher());
                  //ConvexShape convexShape = (ConvexShape)body.getCollisionShape();
                  SphereShape tmpSphere = new SphereShape(body.getCcdSweptSphereRadius()); //btConvexShape* convexShape = static_cast<btConvexShape*>(body->getCollisionShape());

                  sweepResults.collisionFilterGroup = body.getBroadphaseProxy().collisionFilterGroup;
                  sweepResults.collisionFilterMask = body.getBroadphaseProxy().collisionFilterMask;

                  convexSweepTest(tmpSphere, body.getWorldTransform(tmpTrans), predictedTrans, sweepResults);
                  // JAVA NOTE: added closestHitFraction test to prevent objects being stuck
                  if (sweepResults.hasHit() && (sweepResults.closestHitFraction > 0.0001f)) {
                    body.setHitFraction(sweepResults.closestHitFraction);
                    body.predictIntegratedTransform(timeStep * body.getHitFraction(), predictedTrans);
                    body.setHitFraction(0f);
                    //System.out.printf("clamped integration to hit fraction = %f\n", sweepResults.closestHitFraction);
                  }
                }
              }
              finally {
                BulletStats.popProfile();
              }
            }

            body.proceedToTransform(predictedTrans);
          }
        }
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }
 
  protected void predictUnconstraintMotion(float timeStep) {
    BulletStats.pushProfile("predictUnconstraintMotion");
    try {
      Transform tmpTrans = Stack.alloc(Transform.class);
     
      for (int i = 0; i < collisionObjects.size(); i++) {
        CollisionObject colObj = collisionObjects.getQuick(i);
        RigidBody body = RigidBody.upcast(colObj);
        if (body != null) {
          if (!body.isStaticOrKinematicObject()) {
            if (body.isActive()) {
              body.integrateVelocities(timeStep);
              // damping
              body.applyDamping(timeStep);

              body.predictIntegratedTransform(timeStep, body.getInterpolationWorldTransform(tmpTrans));
            }
          }
        }
      }
    }
    finally {
      BulletStats.popProfile();
    }
  }
 
  protected void startProfiling(float timeStep) {
    //#ifndef BT_NO_PROFILE
        CProfileManager.reset();
    //#endif //BT_NO_PROFILE
  }

  protected void debugDrawSphere(float radius, Transform transform, Vector3f color) {
    Vector3f start = Stack.alloc(transform.origin);

    Vector3f xoffs = Stack.alloc(Vector3f.class);
    xoffs.set(radius, 0, 0);
    transform.basis.transform(xoffs);
    Vector3f yoffs = Stack.alloc(Vector3f.class);
    yoffs.set(0, radius, 0);
    transform.basis.transform(yoffs);
    Vector3f zoffs = Stack.alloc(Vector3f.class);
    zoffs.set(0, 0, radius);
    transform.basis.transform(zoffs);

    Vector3f tmp1 = Stack.alloc(Vector3f.class);
    Vector3f tmp2 = Stack.alloc(Vector3f.class);

    // XY
    tmp1.sub(start, xoffs);
    tmp2.add(start, yoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, yoffs);
    tmp2.add(start, xoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, xoffs);
    tmp2.sub(start, yoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.sub(start, yoffs);
    tmp2.sub(start, xoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);

    // XZ
    tmp1.sub(start, xoffs);
    tmp2.add(start, zoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, zoffs);
    tmp2.add(start, xoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, xoffs);
    tmp2.sub(start, zoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.sub(start, zoffs);
    tmp2.sub(start, xoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);

    // YZ
    tmp1.sub(start, yoffs);
    tmp2.add(start, zoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, zoffs);
    tmp2.add(start, yoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.add(start, yoffs);
    tmp2.sub(start, zoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
    tmp1.sub(start, zoffs);
    tmp2.sub(start, yoffs);
    getDebugDrawer().drawLine(tmp1, tmp2, color);
  }
 
  public void debugDrawObject(Transform worldTransform, CollisionShape shape, Vector3f color) {
    Vector3f tmp = Stack.alloc(Vector3f.class);
    Vector3f tmp2 = Stack.alloc(Vector3f.class);

    // Draw a small simplex at the center of the object
    {
      Vector3f start = Stack.alloc(worldTransform.origin);

      tmp.set(1f, 0f, 0f);
      worldTransform.basis.transform(tmp);
      tmp.add(start);
      tmp2.set(1f, 0f, 0f);
      getDebugDrawer().drawLine(start, tmp, tmp2);

      tmp.set(0f, 1f, 0f);
      worldTransform.basis.transform(tmp);
      tmp.add(start);
      tmp2.set(0f, 1f, 0f);
      getDebugDrawer().drawLine(start, tmp, tmp2);

      tmp.set(0f, 0f, 1f);
      worldTransform.basis.transform(tmp);
      tmp.add(start);
      tmp2.set(0f, 0f, 1f);
      getDebugDrawer().drawLine(start, tmp, tmp2);
    }

    // JAVA TODO: debugDrawObject, note that this commented code is from old version, use actual version when implementing
   
//    if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
//    {
//      const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
//      for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--)
//      {
//        btTransform childTrans = compoundShape->getChildTransform(i);
//        const btCollisionShape* colShape = compoundShape->getChildShape(i);
//        debugDrawObject(worldTransform*childTrans,colShape,color);
//      }
//
//    } else
//    {
//      switch (shape->getShapeType())
//      {
//
//      case SPHERE_SHAPE_PROXYTYPE:
//        {
//          const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
//          btScalar radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin
//
//          debugDrawSphere(radius, worldTransform, color);
//          break;
//        }
//      case MULTI_SPHERE_SHAPE_PROXYTYPE:
//        {
//          const btMultiSphereShape* multiSphereShape = static_cast<const btMultiSphereShape*>(shape);
//
//          for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--)
//          {
//            btTransform childTransform = worldTransform;
//            childTransform.getOrigin() += multiSphereShape->getSpherePosition(i);
//            debugDrawSphere(multiSphereShape->getSphereRadius(i), childTransform, color);
//          }
//
//          break;
//        }
//      case CAPSULE_SHAPE_PROXYTYPE:
//        {
//          const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
//
//          btScalar radius = capsuleShape->getRadius();
//          btScalar halfHeight = capsuleShape->getHalfHeight();
//
//          // Draw the ends
//          {
//            btTransform childTransform = worldTransform;
//            childTransform.getOrigin() = worldTransform * btVector3(0,halfHeight,0);
//            debugDrawSphere(radius, childTransform, color);
//          }
//
//          {
//            btTransform childTransform = worldTransform;
//            childTransform.getOrigin() = worldTransform * btVector3(0,-halfHeight,0);
//            debugDrawSphere(radius, childTransform, color);
//          }
//
//          // Draw some additional lines
//          btVector3 start = worldTransform.getOrigin();
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(-radius,halfHeight,0),start+worldTransform.getBasis() * btVector3(-radius,-halfHeight,0), color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(radius,halfHeight,0),start+worldTransform.getBasis() * btVector3(radius,-halfHeight,0), color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(0,halfHeight,-radius),start+worldTransform.getBasis() * btVector3(0,-halfHeight,-radius), color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(0,halfHeight,radius),start+worldTransform.getBasis() * btVector3(0,-halfHeight,radius), color);
//
//          break;
//        }
//      case CONE_SHAPE_PROXYTYPE:
//        {
//          const btConeShape* coneShape = static_cast<const btConeShape*>(shape);
//          btScalar radius = coneShape->getRadius();//+coneShape->getMargin();
//          btScalar height = coneShape->getHeight();//+coneShape->getMargin();
//          btVector3 start = worldTransform.getOrigin();
//
//          int upAxis= coneShape->getConeUpIndex();
//
//
//          btVector3  offsetHeight(0,0,0);
//          offsetHeight[upAxis] = height * btScalar(0.5);
//          btVector3  offsetRadius(0,0,0);
//          offsetRadius[(upAxis+1)%3] = radius;
//          btVector3  offset2Radius(0,0,0);
//          offset2Radius[(upAxis+2)%3] = radius;
//
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight+offsetRadius),color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight-offsetRadius),color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight+offset2Radius),color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight-offset2Radius),color);
//
//
//
//          break;
//
//        }
//      case CYLINDER_SHAPE_PROXYTYPE:
//        {
//          const btCylinderShape* cylinder = static_cast<const btCylinderShape*>(shape);
//          int upAxis = cylinder->getUpAxis();
//          btScalar radius = cylinder->getRadius();
//          btScalar halfHeight = cylinder->getHalfExtentsWithMargin()[upAxis];
//          btVector3 start = worldTransform.getOrigin();
//          btVector3  offsetHeight(0,0,0);
//          offsetHeight[upAxis] = halfHeight;
//          btVector3  offsetRadius(0,0,0);
//          offsetRadius[(upAxis+1)%3] = radius;
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight+offsetRadius),start+worldTransform.getBasis() * (-offsetHeight+offsetRadius),color);
//          getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight-offsetRadius),start+worldTransform.getBasis() * (-offsetHeight-offsetRadius),color);
//          break;
//        }
//      default:
//        {
//
//          if (shape->isConcave())
//          {
//            btConcaveShape* concaveMesh = (btConcaveShape*) shape;
//
//            //todo pass camera, for some culling
//            btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30));
//            btVector3 aabbMin(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30));
//
//            DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color);
//            concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax);
//
//          }
//
//          if (shape->getShapeType() == CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE)
//          {
//            btConvexTriangleMeshShape* convexMesh = (btConvexTriangleMeshShape*) shape;
//            //todo: pass camera for some culling     
//            btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30));
//            btVector3 aabbMin(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30));
//            //DebugDrawcallback drawCallback;
//            DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color);
//            convexMesh->getMeshInterface()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax);
//          }
//
//
//          /// for polyhedral shapes
//          if (shape->isPolyhedral())
//          {
//            btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape;
//
//            int i;
//            for (i=0;i<polyshape->getNumEdges();i++)
//            {
//              btPoint3 a,b;
//              polyshape->getEdge(i,a,b);
//              btVector3 wa = worldTransform * a;
//              btVector3 wb = worldTransform * b;
//              getDebugDrawer()->drawLine(wa,wb,color);
//
//            }
//
//
//          }
//        }
//      }
//    }
  }
 
  @Override
  public void setConstraintSolver(ConstraintSolver solver) {
    if (ownsConstraintSolver) {
      //btAlignedFree( m_constraintSolver);
    }
    ownsConstraintSolver = false;
    constraintSolver = solver;
  }

  @Override
  public ConstraintSolver getConstraintSolver() {
    return constraintSolver;
  }

  @Override
  public int getNumConstraints() {
    return constraints.size();
  }

  @Override
  public TypedConstraint getConstraint(int index) {
    return constraints.getQuick(index);
  }

  // JAVA NOTE: not part of the original api
  @Override
  public int getNumActions() {
    return actions.size();
  }

  // JAVA NOTE: not part of the original api
  @Override
  public ActionInterface getAction(int index) {
    return actions.getQuick(index);
  }

  public SimulationIslandManager getSimulationIslandManager() {
    return islandManager;
  }

  public CollisionWorld getCollisionWorld() {
    return this;
  }

  @Override
  public DynamicsWorldType getWorldType() {
    return DynamicsWorldType.DISCRETE_DYNAMICS_WORLD;
  }

  public void setNumTasks(int numTasks) {
  }

        public void setPreTickCallback(InternalTickCallback callback){
                preTickCallback = callback;
        }

  ////////////////////////////////////////////////////////////////////////////
 
  private static final Comparator<TypedConstraint> sortConstraintOnIslandPredicate = new Comparator<TypedConstraint>() {
    public int compare(TypedConstraint lhs, TypedConstraint rhs) {
      int rIslandId0, lIslandId0;
      rIslandId0 = getConstraintIslandId(rhs);
      lIslandId0 = getConstraintIslandId(lhs);
      return lIslandId0 < rIslandId0? -1 : +1;
    }
  };
 
//  private static class DebugDrawcallback implements TriangleCallback, InternalTriangleIndexCallback {
//    private IDebugDraw debugDrawer;
//    private final Vector3f color = new Vector3f();
//    private final Transform worldTrans = new Transform();
//
//    public DebugDrawcallback(IDebugDraw debugDrawer, Transform worldTrans, Vector3f color) {
//      this.debugDrawer = debugDrawer;
//      this.worldTrans.set(worldTrans);
//      this.color.set(color);
//    }
//
//    public void internalProcessTriangleIndex(Vector3f[] triangle, int partId, int triangleIndex) {
//      processTriangle(triangle,partId,triangleIndex);
//    }
//
//    private final Vector3f wv0 = new Vector3f(),wv1 = new Vector3f(),wv2 = new Vector3f();
//
//    public void processTriangle(Vector3f[] triangle, int partId, int triangleIndex) {
//      wv0.set(triangle[0]);
//      worldTrans.transform(wv0);
//      wv1.set(triangle[1]);
//      worldTrans.transform(wv1);
//      wv2.set(triangle[2]);
//      worldTrans.transform(wv2);
//
//      debugDrawer.drawLine(wv0, wv1, color);
//      debugDrawer.drawLine(wv1, wv2, color);
//      debugDrawer.drawLine(wv2, wv0, color);
//    }
//  }

  private static class ClosestNotMeConvexResultCallback extends ClosestConvexResultCallback {
    private CollisionObject me;
    private float allowedPenetration = 0f;
    private OverlappingPairCache pairCache;
    private Dispatcher dispatcher;

    public ClosestNotMeConvexResultCallback(CollisionObject me, Vector3f fromA, Vector3f toA, OverlappingPairCache pairCache, Dispatcher dispatcher) {
      super(fromA, toA);
      this.me = me;
      this.pairCache = pairCache;
      this.dispatcher = dispatcher;
    }

    @Override
    public float addSingleResult(LocalConvexResult convexResult, boolean normalInWorldSpace) {
      if (convexResult.hitCollisionObject == me) {
        return 1f;
      }

      Vector3f linVelA = Stack.alloc(Vector3f.class), linVelB = Stack.alloc(Vector3f.class);
      linVelA.sub(convexToWorld, convexFromWorld);
      linVelB.set(0f, 0f, 0f);//toB.getOrigin()-fromB.getOrigin();

      Vector3f relativeVelocity = Stack.alloc(Vector3f.class);
      relativeVelocity.sub(linVelA, linVelB);
      // don't report time of impact for motion away from the contact normal (or causes minor penetration)
      if (convexResult.hitNormalLocal.dot(relativeVelocity) >= -allowedPenetration) {
        return 1f;
      }

      return super.addSingleResult(convexResult, normalInWorldSpace);
    }

    @Override
    public boolean needsCollision(BroadphaseProxy proxy0) {
      // don't collide with itself
      if (proxy0.clientObject == me) {
        return false;
      }

      // don't do CCD when the collision filters are not matching
      if (!super.needsCollision(proxy0)) {
        return false;
      }

      CollisionObject otherObj = (CollisionObject)proxy0.clientObject;

      // call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179
      if (dispatcher.needsResponse(me, otherObj)) {
        // don't do CCD when there are already contact points (touching contact/penetration)
        ObjectArrayList<PersistentManifold> manifoldArray = new ObjectArrayList<PersistentManifold>();
        BroadphasePair collisionPair = pairCache.findPair(me.getBroadphaseHandle(), proxy0);
        if (collisionPair != null) {
          if (collisionPair.algorithm != null) {
            //manifoldArray.resize(0);
            collisionPair.algorithm.getAllContactManifolds(manifoldArray);
            for (int j=0; j<manifoldArray.size(); j++) {
              PersistentManifold manifold = manifoldArray.getQuick(j);
              if (manifold.getNumContacts() > 0) {
                return false;
              }
            }
          }
        }
      }
      return true;
    }
  }

}
TOP

Related Classes of com.bulletphysics.dynamics.DiscreteDynamicsWorld$InplaceSolverIslandCallback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.