Package com.bulletphysics.demos.forklift

Source Code of com.bulletphysics.demos.forklift.ForkLiftDemo

/*
* 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.demos.forklift;

import com.bulletphysics.util.ObjectArrayList;
import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.DbvtBroadphase;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.shapes.BoxShape;
import com.bulletphysics.collision.shapes.BvhTriangleMeshShape;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.CompoundShape;
import com.bulletphysics.collision.shapes.CylinderShapeX;
import com.bulletphysics.collision.shapes.TriangleIndexVertexArray;
import com.bulletphysics.demos.opengl.DemoApplication;
import com.bulletphysics.demos.opengl.GLDebugDrawer;
import com.bulletphysics.demos.opengl.GLShapeDrawer;
import com.bulletphysics.demos.opengl.IGL;
import com.bulletphysics.demos.opengl.LWJGL;
import com.bulletphysics.dynamics.DiscreteDynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.HingeConstraint;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.SliderConstraint;
import com.bulletphysics.dynamics.vehicle.DefaultVehicleRaycaster;
import com.bulletphysics.dynamics.vehicle.RaycastVehicle;
import com.bulletphysics.dynamics.vehicle.VehicleRaycaster;
import com.bulletphysics.dynamics.vehicle.VehicleTuning;
import com.bulletphysics.dynamics.vehicle.WheelInfo;
import com.bulletphysics.linearmath.DebugDrawModes;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.Transform;
import java.awt.event.KeyEvent;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.vecmath.Vector3f;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import static com.bulletphysics.demos.opengl.IGL.*;

/**
*
* @author jezek2
*/
public class ForkLiftDemo extends DemoApplication {

  public static final float PI = 3.14159265358979323846f;
  public static final float PI_2 = 1.57079632679489661923f;
  public static final float PI_4 = 0.785398163397448309616f;

  public static final float LIFT_EPS = 0.0000001f;
  // By default, Bullet Vehicle uses Y as up axis.
  // You can override the up axis, for example Z-axis up. Enable this define to see how to:
  ////#define FORCE_ZAXIS_UP 1

  //#ifdef FORCE_ZAXIS_UP
  //private int rightIndex = 0;
  //private int upIndex = 2;
  //private int forwardIndex = 1;
  //private btVector3 wheelDirectionCS0(0,0,-1);
  //private btVector3 wheelAxleCS(1,0,0);
  //#else
  private int rightIndex = 0;
  private int upIndex = 1;
  private int forwardIndex = 2;
  private final Vector3f wheelDirectionCS0 = new Vector3f(0, -1, 0);
  private final Vector3f wheelAxleCS = new Vector3f(-1, 0, 0);
  //#endif

  private static final int maxProxies = 32766;
  private static final int maxOverlap = 65535;

  // RaycastVehicle is the interface for the constraint that implements the raycast vehicle
  // notice that for higher-quality slow-moving vehicles, another approach might be better
  // implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
  private float gEngineForce = 0.f;

  private float defaultBreakingForce = 10.f;
  private float gBreakingForce = 10.f;

  private float maxEngineForce = 1000.f;//this should be engine/velocity dependent
  private float maxBreakingForce = 100.f;

  private float gVehicleSteering = 0.f;
  private float steeringIncrement = 0.04f;
  private float steeringClamp = 0.3f;
  private float wheelRadius = 0.5f;
  private float wheelWidth = 0.4f;
  private float wheelFriction = 1000;//1e30f;
  private float suspensionStiffness = 20.f;
  private float suspensionDamping = 2.3f;
  private float suspensionCompression = 4.4f;
  private float rollInfluence = 0.1f;//1.0f;

  private float suspensionRestLength = 0.6f;

  private static final float CUBE_HALF_EXTENTS = 1f;
 
  ////////////////////////////////////////////////////////////////////////////
 
 
  public RigidBody carChassis;

  //----------------------------
 
  public RigidBody liftBody;
  public final Vector3f liftStartPos = new Vector3f();
  public HingeConstraint liftHinge;

  public RigidBody forkBody;
  public Vector3f forkStartPos = new Vector3f();
  public SliderConstraint forkSlider;

  public RigidBody loadBody;
  public Vector3f loadStartPos = new Vector3f();

  public boolean useDefaultCamera;

  //----------------------------

  public ObjectArrayList<CollisionShape> collisionShapes = new ObjectArrayList<CollisionShape>();
  public BroadphaseInterface overlappingPairCache;
  public CollisionDispatcher dispatcher;
  public ConstraintSolver constraintSolver;
  public DefaultCollisionConfiguration collisionConfiguration;
  public TriangleIndexVertexArray indexVertexArrays;
  public ByteBuffer vertices;

  public VehicleTuning tuning = new VehicleTuning();
  public VehicleRaycaster vehicleRayCaster;
  public RaycastVehicle vehicle;

  public float cameraHeight = 4f;
  public float minCameraDistance = 3f;
  public float maxCameraDistance = 10f;

  public ForkLiftDemo(IGL gl) {
    super(gl);
    cameraPosition.set(30, 30, 30);
    useDefaultCamera = false;
  }

  public void lockLiftHinge() {
    float hingeAngle = liftHinge.getHingeAngle();
    float lowLim = liftHinge.getLowerLimit();
    float hiLim = liftHinge.getUpperLimit();
    liftHinge.enableAngularMotor(false, 0, 0);
    if (hingeAngle < lowLim) {
      liftHinge.setLimit(lowLim, lowLim + LIFT_EPS);
    }
    else if (hingeAngle > hiLim) {
      liftHinge.setLimit(hiLim - LIFT_EPS, hiLim);
    }
    else {
      liftHinge.setLimit(hingeAngle - LIFT_EPS, hingeAngle + LIFT_EPS);
    }
  }

  public void lockForkSlider() {
    float linDepth = forkSlider.getLinearPos();
    float lowLim = forkSlider.getLowerLinLimit();
    float hiLim = forkSlider.getUpperLinLimit();
    forkSlider.setPoweredLinMotor(false);
    if (linDepth <= lowLim) {
      forkSlider.setLowerLinLimit(lowLim);
      forkSlider.setUpperLinLimit(lowLim);
    }
    else if (linDepth > hiLim) {
      forkSlider.setLowerLinLimit(hiLim);
      forkSlider.setUpperLinLimit(hiLim);
    }
    else {
      forkSlider.setLowerLinLimit(linDepth);
      forkSlider.setUpperLinLimit(linDepth);
    }
  }

  @Override
  public void clientMoveAndDisplay() {
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);

    {     
      int wheelIndex = 2;
      vehicle.applyEngineForce(gEngineForce,wheelIndex);
      vehicle.setBrake(gBreakingForce,wheelIndex);
      wheelIndex = 3;
      vehicle.applyEngineForce(gEngineForce,wheelIndex);
      vehicle.setBrake(gBreakingForce,wheelIndex);

      wheelIndex = 0;
      vehicle.setSteeringValue(gVehicleSteering,wheelIndex);
      wheelIndex = 1;
      vehicle.setSteeringValue(gVehicleSteering,wheelIndex);
    }

    float dt = getDeltaTimeMicroseconds() * 0.000001f;
   
    if (dynamicsWorld != null)
    {
      // during idle mode, just run 1 simulation step maximum
      int maxSimSubSteps = idle ? 1 : 2;
      if (idle)
        dt = 1f/420f;

      int numSimSteps = dynamicsWorld.stepSimulation(dt,maxSimSubSteps);

      //#define VERBOSE_FEEDBACK
      //#ifdef VERBOSE_FEEDBACK
      //if (!numSimSteps)
      //  printf("Interpolated transforms\n");
      //else
      //{
      //  if (numSimSteps > maxSimSubSteps)
      //  {
      //    //detect dropping frames
      //    printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps);
      //  } else
      //  {
      //    printf("Simulated (%i) steps\n",numSimSteps);
      //  }
      //}
      //#endif //VERBOSE_FEEDBACK
    }

    //#ifdef USE_QUICKPROF
    //btProfiler::beginBlock("render");
    //#endif //USE_QUICKPROF

    renderme();
   
    // optional but useful: debug drawing
    if (dynamicsWorld != null) {
      dynamicsWorld.debugDrawWorld();
    }

    //#ifdef USE_QUICKPROF
    //btProfiler::endBlock("render");
    //#endif
  }

  @Override
  public void clientResetScene() {
    gVehicleSteering = 0.f;
    Transform tr = new Transform();
    tr.setIdentity();
    carChassis.setCenterOfMassTransform(tr);
    carChassis.setLinearVelocity(new Vector3f(0,0,0));
    carChassis.setAngularVelocity(new Vector3f(0,0,0));
    dynamicsWorld.getBroadphase().getOverlappingPairCache().cleanProxyFromPairs(carChassis.getBroadphaseHandle(),getDynamicsWorld().getDispatcher());
    if (vehicle != null)
    {
      vehicle.resetSuspension();
      for (int i=0;i<vehicle.getNumWheels();i++)
      {
        // synchronize the wheels with the (interpolated) chassis worldtransform
        vehicle.updateWheelTransform(i,true);
      }
    }
    Transform liftTrans = new Transform();
    liftTrans.setIdentity();
    liftTrans.origin.set(liftStartPos);
    liftBody.activate();
    liftBody.setCenterOfMassTransform(liftTrans);
    liftBody.setLinearVelocity(new Vector3f(0,0,0));
    liftBody.setAngularVelocity(new Vector3f(0,0,0));

    Transform forkTrans = new Transform();
    forkTrans.setIdentity();
    forkTrans.origin.set(forkStartPos);
    forkBody.activate();
    forkBody.setCenterOfMassTransform(forkTrans);
    forkBody.setLinearVelocity(new Vector3f(0,0,0));
    forkBody.setAngularVelocity(new Vector3f(0,0,0));

    liftHinge.setLimit(-LIFT_EPS, LIFT_EPS);
    liftHinge.enableAngularMotor(false, 0, 0);

    forkSlider.setLowerLinLimit(0.1f);
    forkSlider.setUpperLinLimit(0.1f);
    forkSlider.setPoweredLinMotor(false);

    Transform loadTrans = new Transform();
    loadTrans.setIdentity();
    loadTrans.origin.set(loadStartPos);
    loadBody.activate();
    loadBody.setCenterOfMassTransform(loadTrans);
    loadBody.setLinearVelocity(new Vector3f(0,0,0));
    loadBody.setAngularVelocity(new Vector3f(0,0,0));
  }

  @Override
  public void displayCallback() {
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);

    renderme();
   
    // optional but useful: debug drawing
    if (dynamicsWorld != null) {
      dynamicsWorld.debugDrawWorld();
    }
  }

  ///a very basic camera following the vehicle
  @Override
  public void updateCamera() {
    if(useDefaultCamera)
    {
      super.updateCamera();
      return;
    }
   
    // //#define DISABLE_CAMERA 1
    //#ifdef DISABLE_CAMERA
    //DemoApplication::updateCamera();
    //return;
    //#endif //DISABLE_CAMERA

    gl.glMatrixMode(gl.GL_PROJECTION);
    gl.glLoadIdentity();

    Transform chassisWorldTrans = new Transform();

    // look at the vehicle
    carChassis.getMotionState().getWorldTransform(chassisWorldTrans);
    cameraTargetPosition.set(chassisWorldTrans.origin);

    // interpolate the camera height
    //#ifdef FORCE_ZAXIS_UP
    //m_cameraPosition[2] = (15.0*m_cameraPosition[2] + m_cameraTargetPosition[2] + m_cameraHeight)/16.0;
    //#else
    cameraPosition.y = (15.0f*cameraPosition.y + cameraTargetPosition.y + cameraHeight) / 16.0f;
    //#endif

    Vector3f camToObject = new Vector3f();
    camToObject.sub(cameraTargetPosition, cameraPosition);

    // keep distance between min and max distance
    float cameraDistance = camToObject.length();
    float correctionFactor = 0f;
    if (cameraDistance < minCameraDistance)
    {
      correctionFactor = 0.15f*(minCameraDistance-cameraDistance)/cameraDistance;
    }
    if (cameraDistance > maxCameraDistance)
    {
      correctionFactor = 0.15f*(maxCameraDistance-cameraDistance)/cameraDistance;
    }
    Vector3f tmp = new Vector3f();
    tmp.scale(correctionFactor, camToObject);
    cameraPosition.sub(tmp);

    // update OpenGL camera settings
    gl.glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);

    gl.glMatrixMode(IGL.GL_MODELVIEW);
    gl.glLoadIdentity();
   
    gl.gluLookAt(cameraPosition.x,cameraPosition.y,cameraPosition.z,
          cameraTargetPosition.x,cameraTargetPosition.y, cameraTargetPosition.z,
          cameraUp.x,cameraUp.y,cameraUp.z);
  }

  @Override
  public void specialKeyboard(int key, int x, int y, int modifiers) {
    if (key == Keyboard.KEY_END) {
      return;
    }

    if ((modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0) {
      switch (key) {
        case Keyboard.KEY_LEFT: {
          liftHinge.setLimit(-PI / 16.0f, PI / 8.0f);
          liftHinge.enableAngularMotor(true, -0.1f, 10.0f);
          break;
        }
        case Keyboard.KEY_RIGHT: {
          liftHinge.setLimit(-PI / 16.0f, PI / 8.0f);
          liftHinge.enableAngularMotor(true, 0.1f, 10.0f);
          break;
        }
        case Keyboard.KEY_UP: {
          forkSlider.setLowerLinLimit(0.1f);
          forkSlider.setUpperLinLimit(3.9f);
          forkSlider.setPoweredLinMotor(true);
          forkSlider.setMaxLinMotorForce(10.0f);
          forkSlider.setTargetLinMotorVelocity(1.0f);
          break;
        }
        case Keyboard.KEY_DOWN: {
          forkSlider.setLowerLinLimit(0.1f);
          forkSlider.setUpperLinLimit(3.9f);
          forkSlider.setPoweredLinMotor(true);
          forkSlider.setMaxLinMotorForce(10.0f);
          forkSlider.setTargetLinMotorVelocity(-1.0f);
          break;
        }

        default:
          super.specialKeyboard(key, x, y, modifiers);
          break;
      }

    } else {
      switch (key) {
        case Keyboard.KEY_LEFT: {
          gVehicleSteering += steeringIncrement;
          if (gVehicleSteering > steeringClamp) {
            gVehicleSteering = steeringClamp;
          }
          break;
        }
        case Keyboard.KEY_RIGHT: {
          gVehicleSteering -= steeringIncrement;
          if (gVehicleSteering < -steeringClamp) {
            gVehicleSteering = -steeringClamp;
          }
          break;
        }
        case Keyboard.KEY_UP: {
          gEngineForce = maxEngineForce;
          gBreakingForce = 0.f;
          break;
        }
        case Keyboard.KEY_DOWN: {
          gEngineForce = -maxEngineForce;
          gBreakingForce = 0.f;
          break;
        }

        case Keyboard.KEY_F5:
          useDefaultCamera = !useDefaultCamera;
          break;
        default:
          super.specialKeyboard(key, x, y, modifiers);
          break;
      }

    }
    //glutPostRedisplay();
  }

  @Override
  public void specialKeyboardUp(int key, int x, int y, int modifiers) {
    switch (key) {
      case Keyboard.KEY_UP: {
        lockForkSlider();
        gEngineForce = 0.f;
        gBreakingForce = defaultBreakingForce;
        break;
      }
      case Keyboard.KEY_DOWN: {
        lockForkSlider();
        gEngineForce = 0.f;
        gBreakingForce = defaultBreakingForce;
        break;
      }
      case Keyboard.KEY_LEFT:
      case Keyboard.KEY_RIGHT: {
        lockLiftHinge();
        break;
      }
      default:
        super.specialKeyboardUp(key, x, y, modifiers);
        break;
    }
  }

  @Override
  public void renderme() {
    updateCamera();

    //float[] m = new float[16];
    //int i;

    CylinderShapeX wheelShape = new CylinderShapeX(new Vector3f(wheelWidth,wheelRadius,wheelRadius));
    Vector3f wheelColor = new Vector3f(1,0,0);

    Vector3f worldBoundsMin = new Vector3f(),worldBoundsMax = new Vector3f();
    getDynamicsWorld().getBroadphase().getBroadphaseAabb(worldBoundsMin,worldBoundsMax);

    for (int i=0;i<vehicle.getNumWheels();i++)
    {
      // synchronize the wheels with the (interpolated) chassis worldtransform
      vehicle.updateWheelTransform(i,true);
      // draw wheels (cylinders)
      Transform trans = vehicle.getWheelInfo(i).worldTransform;
      GLShapeDrawer.drawOpenGL(gl,trans,wheelShape,wheelColor,getDebugMode()/*,worldBoundsMin,worldBoundsMax*/);
    }
   
    super.renderme();

    if ((getDebugMode() & DebugDrawModes.NO_HELP_TEXT) == 0) {
      setOrthographicProjection();
      gl.glDisable(GL_LIGHTING);
      gl.glColor3f(0, 0, 0);

      drawString("SHIFT+Cursor Left/Right - rotate lift", 350, 20, TEXT_COLOR);
      drawString("SHIFT+Cursor UP/Down - move fork up/down", 350, 40, TEXT_COLOR);
      drawString("F5 - toggle camera mode", 350, 60, TEXT_COLOR);

      resetPerspectiveProjection();
      gl.glEnable(GL_LIGHTING);
    }
  }

  @Override
  public void initPhysics() {
    //#ifdef FORCE_ZAXIS_UP
    //cameraUp.set(0,0,1);
    //forwardAxis = 1;
    //#endif

    CollisionShape groundShape = new BoxShape(new Vector3f(50,3,50));
    collisionShapes.add(groundShape);
    collisionConfiguration = new DefaultCollisionConfiguration();
    dispatcher = new CollisionDispatcher(collisionConfiguration);
    Vector3f worldMin = new Vector3f(-1000,-1000,-1000);
    Vector3f worldMax = new Vector3f(1000,1000,1000);
    //overlappingPairCache = new AxisSweep3(worldMin,worldMax);
    overlappingPairCache = new DbvtBroadphase();
    constraintSolver = new SequentialImpulseConstraintSolver();
    dynamicsWorld = new DiscreteDynamicsWorld(dispatcher,overlappingPairCache,constraintSolver,collisionConfiguration);
    //#ifdef FORCE_ZAXIS_UP
    //m_dynamicsWorld->setGravity(btVector3(0,0,-10));
    //#endif

    //m_dynamicsWorld->setGravity(btVector3(0,0,0));
    Transform tr = new Transform();
    tr.setIdentity();

    // either use heightfield or triangle mesh
    //#define  USE_TRIMESH_GROUND 1
    //#ifdef USE_TRIMESH_GROUND
    final float TRIANGLE_SIZE=20f;

    // create a triangle-mesh ground
    int vertStride = 3*4;
    int indexStride = 3*4;

    final int NUM_VERTS_X = 20;
    final int NUM_VERTS_Y = 20;
    final int totalVerts = NUM_VERTS_X*NUM_VERTS_Y;

    final int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1);

    vertices = ByteBuffer.allocateDirect(totalVerts*vertStride).order(ByteOrder.nativeOrder());
    ByteBuffer gIndices = ByteBuffer.allocateDirect(totalTriangles*3*4).order(ByteOrder.nativeOrder());

    for (int i=0;i<NUM_VERTS_X;i++)
    {
      for (int j=0;j<NUM_VERTS_Y;j++)
      {
        float wl = 0.2f;
        // height set to zero, but can also use curved landscape, just uncomment out the code
        float height = 0.f;//20.f*sinf(float(i)*wl)*cosf(float(j)*wl);
        //#ifdef FORCE_ZAXIS_UP
        //m_vertices[i+j*NUM_VERTS_X].setValue(
        //  (i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
        //  (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE,
        //  height
        //  );
        //#else
        int idx = (i+j*NUM_VERTS_X)*3*4;
        vertices.putFloat(idx+0*4, (i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE);
        vertices.putFloat(idx+1*4, height);
        vertices.putFloat(idx+2*4, (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
        //#endif
      }
    }

    //int index=0;
    for (int i=0;i<NUM_VERTS_X-1;i++)
    {
      for (int j=0;j<NUM_VERTS_Y-1;j++)
      {
        gIndices.putInt(j*NUM_VERTS_X+i);
        gIndices.putInt(j*NUM_VERTS_X+i+1);
        gIndices.putInt((j+1)*NUM_VERTS_X+i+1);

        gIndices.putInt(j*NUM_VERTS_X+i);
        gIndices.putInt((j+1)*NUM_VERTS_X+i+1);
        gIndices.putInt((j+1)*NUM_VERTS_X+i);
      }
    }
    gIndices.flip();

    indexVertexArrays = new TriangleIndexVertexArray(totalTriangles,
      gIndices,
      indexStride,
      totalVerts,vertices,vertStride);

    boolean useQuantizedAabbCompression = true;
    groundShape = new BvhTriangleMeshShape(indexVertexArrays,useQuantizedAabbCompression);

    tr.origin.set(0,-4.5f,0);
    //#else
    ////testing btHeightfieldTerrainShape
    //int width=128;
    //int length=128;
    //unsigned char* heightfieldData = new unsigned char[width*length];
    //{
    //  for (int i=0;i<width*length;i++)
    //  {
    //    heightfieldData[i]=0;
    //  }
    //}
    //
    //char*  filename="heightfield128x128.raw";
    //FILE* heightfieldFile = fopen(filename,"r");
    //if (!heightfieldFile)
    //{
    //  filename="../../heightfield128x128.raw";
    //  heightfieldFile = fopen(filename,"r");
    //}
    //if (heightfieldFile)
    //{
    //  int numBytes =fread(heightfieldData,1,width*length,heightfieldFile);
    //  //btAssert(numBytes);
    //  if (!numBytes)
    //  {
    //    printf("couldn't read heightfield at %s\n",filename);
    //  }
    //  fclose (heightfieldFile);
    //}
    //
    //
    //btScalar maxHeight = 20000.f;
    //
    //bool useFloatDatam=false;
    //bool flipQuadEdges=false;
    //
    //btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(width,length,heightfieldData,maxHeight,upIndex,useFloatDatam,flipQuadEdges);;
    //groundShape = heightFieldShape;
    //
    //heightFieldShape->setUseDiamondSubdivision(true);
    //
    //btVector3 localScaling(20,20,20);
    //localScaling[upIndex]=1.f;
    //groundShape->setLocalScaling(localScaling);
    //
    //tr.setOrigin(btVector3(0,-64.5f,0));
    //
    //#endif //

    collisionShapes.add(groundShape);

    // create ground object
    localCreateRigidBody(0,tr,groundShape);

    //#ifdef FORCE_ZAXIS_UP
    ////   indexRightAxis = 0;
    ////   indexUpAxis = 2;
    ////   indexForwardAxis = 1;
    //btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,2.f, 0.5f));
    //btCompoundShape* compound = new btCompoundShape();
    //btTransform localTrans;
    //localTrans.setIdentity();
    ////localTrans effectively shifts the center of mass with respect to the chassis
    //localTrans.setOrigin(btVector3(0,0,1));
    //#else
    CollisionShape chassisShape = new BoxShape(new Vector3f(1.f,0.5f,2.f));
    collisionShapes.add(chassisShape);

    CompoundShape compound = new CompoundShape();
    collisionShapes.add(compound);
    Transform localTrans = new Transform();
    localTrans.setIdentity();
    // localTrans effectively shifts the center of mass with respect to the chassis
    localTrans.origin.set(0,1,0);
    //#endif

    compound.addChildShape(localTrans,chassisShape);

    {
      CollisionShape suppShape = new BoxShape(new Vector3f(0.5f,0.1f,0.5f));
      collisionShapes.add(chassisShape);
      Transform suppLocalTrans = new Transform();
      suppLocalTrans.setIdentity();
      // localTrans effectively shifts the center of mass with respect to the chassis
      suppLocalTrans.origin.set(0f,1.0f,2.5f);
      compound.addChildShape(suppLocalTrans, suppShape);
    }

    tr.origin.set(0,0.f,0);

    carChassis = localCreateRigidBody(800,tr,compound);//chassisShape);
    //m_carChassis->setDamping(0.2,0.2);


    {
      CollisionShape liftShape = new BoxShape(new Vector3f(0.5f,2.0f,0.05f));
      collisionShapes.add(liftShape);
      Transform liftTrans = new Transform();
      liftStartPos.set(0.0f, 2.5f, 3.05f);
      liftTrans.setIdentity();
      liftTrans.origin.set(liftStartPos);
      liftBody = localCreateRigidBody(10,liftTrans, liftShape);

      Transform localA = new Transform(), localB = new Transform();
      localA.setIdentity();
      localB.setIdentity();
      MatrixUtil.setEulerZYX(localA.basis, 0, PI_2, 0);
      localA.origin.set(0.0f, 1.0f, 3.05f);
      MatrixUtil.setEulerZYX(localB.basis, 0, PI_2, 0);
      localB.origin.set(0.0f, -1.5f, -0.05f);
      liftHinge = new HingeConstraint(carChassis,liftBody, localA, localB);
      liftHinge.setLimit(-LIFT_EPS, LIFT_EPS);
      dynamicsWorld.addConstraint(liftHinge, true);

      CollisionShape forkShapeA = new BoxShape(new Vector3f(1.0f,0.1f,0.1f));
      collisionShapes.add(forkShapeA);
      CompoundShape forkCompound = new CompoundShape();
      collisionShapes.add(forkCompound);
      Transform forkLocalTrans = new Transform();
      forkLocalTrans.setIdentity();
      forkCompound.addChildShape(forkLocalTrans, forkShapeA);

      CollisionShape forkShapeB = new BoxShape(new Vector3f(0.1f,0.02f,0.6f));
      collisionShapes.add(forkShapeB);
      forkLocalTrans.setIdentity();
      forkLocalTrans.origin.set(-0.9f, -0.08f, 0.7f);
      forkCompound.addChildShape(forkLocalTrans, forkShapeB);

      CollisionShape forkShapeC = new BoxShape(new Vector3f(0.1f,0.02f,0.6f));
      collisionShapes.add(forkShapeC);
      forkLocalTrans.setIdentity();
      forkLocalTrans.origin.set(0.9f, -0.08f, 0.7f);
      forkCompound.addChildShape(forkLocalTrans, forkShapeC);

      Transform forkTrans = new Transform();
      forkStartPos.set(0.0f, 0.6f, 3.2f);
      forkTrans.setIdentity();
      forkTrans.origin.set(forkStartPos);
      forkBody = localCreateRigidBody(5, forkTrans, forkCompound);

      localA.setIdentity();
      localB.setIdentity();
      MatrixUtil.setEulerZYX(localA.basis, 0, 0, PI_2);
      localA.origin.set(0.0f, -1.9f, 0.05f);
      MatrixUtil.setEulerZYX(localB.basis, 0, 0, PI_2);
      localB.origin.set(0.0f, 0.0f, -0.1f);
      forkSlider = new SliderConstraint(liftBody, forkBody, localA, localB, true);
      forkSlider.setLowerLinLimit(0.1f);
      forkSlider.setUpperLinLimit(0.1f);
      forkSlider.setLowerAngLimit(-LIFT_EPS);
      forkSlider.setUpperAngLimit(LIFT_EPS);
      dynamicsWorld.addConstraint(forkSlider, true);
     
      CompoundShape loadCompound = new CompoundShape();
      collisionShapes.add(loadCompound);
      CollisionShape loadShapeA = new BoxShape(new Vector3f(2.0f,0.5f,0.5f));
      collisionShapes.add(loadShapeA);
      Transform loadTrans = new Transform();
      loadTrans.setIdentity();
      loadCompound.addChildShape(loadTrans, loadShapeA);
      CollisionShape loadShapeB = new BoxShape(new Vector3f(0.1f,1.0f,1.0f));
      collisionShapes.add(loadShapeB);
      loadTrans.setIdentity();
      loadTrans.origin.set(2.1f, 0.0f, 0.0f);
      loadCompound.addChildShape(loadTrans, loadShapeB);
      CollisionShape loadShapeC = new BoxShape(new Vector3f(0.1f,1.0f,1.0f));
      collisionShapes.add(loadShapeC);
      loadTrans.setIdentity();
      loadTrans.origin.set(-2.1f, 0.0f, 0.0f);
      loadCompound.addChildShape(loadTrans, loadShapeC);
      loadTrans.setIdentity();
      loadStartPos.set(0.0f, -3.5f, 7.0f);
      loadTrans.origin.set(loadStartPos);
      loadBody  = localCreateRigidBody(4, loadTrans, loadCompound);
    }

    clientResetScene();

    // create vehicle
    {

      vehicleRayCaster = new DefaultVehicleRaycaster(dynamicsWorld);
      vehicle = new RaycastVehicle(tuning,carChassis,vehicleRayCaster);

      // never deactivate the vehicle
      carChassis.setActivationState(CollisionObject.DISABLE_DEACTIVATION);

      dynamicsWorld.addVehicle(vehicle);

      float connectionHeight = 1.2f;

      boolean isFrontWheel=true;

      // choose coordinate system
      vehicle.setCoordinateSystem(rightIndex,upIndex,forwardIndex);

      //#ifdef FORCE_ZAXIS_UP
      //btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
      //#else
      Vector3f connectionPointCS0 = new Vector3f(CUBE_HALF_EXTENTS-(0.3f*wheelWidth),connectionHeight,2f*CUBE_HALF_EXTENTS-wheelRadius);
      //#endif

      vehicle.addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,tuning,isFrontWheel);
      //#ifdef FORCE_ZAXIS_UP
      //connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
      //#else
      connectionPointCS0 = new Vector3f(-CUBE_HALF_EXTENTS+(0.3f*wheelWidth),connectionHeight,2f*CUBE_HALF_EXTENTS-wheelRadius);
      //#endif

      vehicle.addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,tuning,isFrontWheel);
      //#ifdef FORCE_ZAXIS_UP
      //connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
      //#else
      connectionPointCS0 = new Vector3f(-CUBE_HALF_EXTENTS+(0.3f*wheelWidth),connectionHeight,-2f*CUBE_HALF_EXTENTS+wheelRadius);
      //#endif //FORCE_ZAXIS_UP
      isFrontWheel = false;
      vehicle.addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,tuning,isFrontWheel);
      //#ifdef FORCE_ZAXIS_UP
      //connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
      //#else
      connectionPointCS0 = new Vector3f(CUBE_HALF_EXTENTS-(0.3f*wheelWidth),connectionHeight,-2f*CUBE_HALF_EXTENTS+wheelRadius);
      //#endif
      vehicle.addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,tuning,isFrontWheel);

      for (int i=0;i<vehicle.getNumWheels();i++)
      {
        WheelInfo wheel = vehicle.getWheelInfo(i);
        wheel.suspensionStiffness = suspensionStiffness;
        wheel.wheelsDampingRelaxation = suspensionDamping;
        wheel.wheelsDampingCompression = suspensionCompression;
        wheel.frictionSlip = wheelFriction;
        wheel.rollInfluence = rollInfluence;
      }
    }

    setCameraDistance(26.f);
  }
 
  public static void main(String[] args) throws LWJGLException {
    ForkLiftDemo forkLiftDemo = new ForkLiftDemo(LWJGL.getGL());
    forkLiftDemo.initPhysics();
    forkLiftDemo.getDynamicsWorld().setDebugDrawer(new GLDebugDrawer(LWJGL.getGL()));

    LWJGL.main(args, 800, 600, "Bullet ForkLift Demo", forkLiftDemo);
  }

}
TOP

Related Classes of com.bulletphysics.demos.forklift.ForkLiftDemo

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.