/* * Java port of Bullet (c) 2008 Martin Dvorak * * 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.vehicle; import java.nio.ByteBuffer; import java.nio.ByteOrder; 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 javax.media.opengl.GL; import com.bulletphysics.dynamics.DynamicsWorld; import com.bulletphysics.dynamics.RigidBody; import com.bulletphysics.dynamics.RigidBodyConstructionInfo; import com.bulletphysics.linearmath.DefaultMotionState; import com.bulletphysics.dynamics.DiscreteDynamicsWorld; import com.bulletphysics.dynamics.RigidBody; import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver; import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver; 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.Transform; import com.bulletphysics.linearmath.Clock; import com.bulletphysics.util.ObjectArrayList; import javax.vecmath.Vector3f; import org.lwjgl.LWJGLException; import org.lwjgl.input.Keyboard; /** * VehicleDemo shows how to setup and use the built-in raycast vehicle. * * @author jezek2 */ public class VehicleDemo extends Object3D // DemoApplication { transient protected DynamicsWorld dynamicsWorld = null; // 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 //int rightIndex = 0; //int upIndex = 2; //int forwardIndex = 1; //btVector3 wheelDirectionCS0(0,0,-1); //btVector3 wheelAxleCS(1,0,0); //#else private static final int rightIndex = 0; private static final int upIndex = 1; private static final int forwardIndex = 2; private static final Vector3f wheelDirectionCS0 = new Vector3f(0,-1,0); private static 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 static float gEngineForce = 0.f; private static float gBreakingForce = 0.f; private static float maxEngineForce = 1000.f;//this should be engine/velocity dependent private static float maxBreakingForce = 100.f; private static float gVehicleSteering = 0.f; private static float steeringIncrement = 0.04f; private static float steeringClamp = 0.3f; private static float wheelRadius = 0.5f; private static float wheelWidth = 0.4f; private static float wheelFriction = 1000;//1e30f; private static float suspensionStiffness = 20.f; private static float suspensionDamping = 2.3f; private static float suspensionCompression = 4.4f; private static float rollInfluence = 0.1f;//1.0f; private static final float suspensionRestLength = 0.6f; private static final int CUBE_HALF_EXTENTS = 1; //////////////////////////////////////////////////////////////////////////// public RigidBody carChassis; public ObjectArrayList collisionShapes = new ObjectArrayList(); 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; public float minCameraDistance; public float maxCameraDistance; public VehicleDemo() { super("RagDoll"); carChassis = null; cameraHeight = 4f; minCameraDistance = 3f; maxCameraDistance = 10f; indexVertexArrays = null; vertices = null; vehicle = null; initPhysics(); } public RigidBody localCreateRigidBody(float mass, Transform startTransform, CollisionShape shape) { // rigidbody is dynamic if and only if mass is non zero, otherwise static boolean isDynamic = (mass != 0f); Vector3f localInertia = new Vector3f(0f, 0f, 0f); if (isDynamic) { shape.calculateLocalInertia(mass, localInertia); } // using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects //#define USE_MOTIONSTATE 1 //#ifdef USE_MOTIONSTATE DefaultMotionState myMotionState = new DefaultMotionState(startTransform); RigidBodyConstructionInfo cInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia); RigidBody body = new RigidBody(cInfo); //#else //btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); //body->setWorldTransform(startTransform); //#endif// dynamicsWorld.addRigidBody(body); return body; } // public VehicleDemo(IGL gl) { // super(gl); // carChassis = null; // cameraHeight = 4f; // minCameraDistance = 3f; // maxCameraDistance = 10f; // indexVertexArrays = null; // vertices = null; // vehicle = null; // cameraPosition.set(30, 30, 30); // } public void initPhysics() { //#ifdef FORCE_ZAXIS_UP //m_cameraUp = btVector3(0,0,1); //m_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 SimpleBroadphase(); overlappingPairCache = new DbvtBroadphase(); constraintSolver = new SequentialImpulseConstraintSolver(); dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, overlappingPairCache, constraintSolver, collisionConfiguration); //#ifdef FORCE_ZAXIS_UP //dynamicsWorld.setGravity(new Vector3f(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 = 4 * 3 /* sizeof(btVector3) */; int indexStride = 3 * 4 /* 3*sizeof(int) */; 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()); Vector3f tmp = new Vector3f(); 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 = 0f; // 20f * (float)Math.sin(i * wl) * (float)Math.cos(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 tmp.set( (i - NUM_VERTS_X * 0.5f) * TRIANGLE_SIZE, height, (j - NUM_VERTS_Y * 0.5f) * TRIANGLE_SIZE); int index = i + j * NUM_VERTS_X; vertices.putFloat((index * 3 + 0) * 4, tmp.x); vertices.putFloat((index * 3 + 1) * 4, tmp.y); vertices.putFloat((index * 3 + 2) * 4, tmp.z); //#endif } } //int index=0; gIndices.clear(); 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;isetUseDiamondSubdivision(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.0f, 0.5f, 2.0f)); 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); tr.origin.set(0, 0, 0); carChassis = localCreateRigidBody(800, tr, compound); //chassisShape); //m_carChassis->setDamping(0.2,0.2); 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.set(-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.set(-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.set(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); } boolean Event(double prob) { return Math.random() < prob; } void update() { if (Event(0.1)) { // gVehicleSteering += steeringIncrement; if (gVehicleSteering > steeringClamp) { gVehicleSteering = steeringClamp; } } if (Event(0.1)) { // gVehicleSteering -= steeringIncrement; if (gVehicleSteering < -steeringClamp) { gVehicleSteering = -steeringClamp; } } if (Event(0.5)) { // gEngineForce = maxEngineForce; gBreakingForce = 0.f; } if (Event(0.5)) { // gBreakingForce = maxBreakingForce; gEngineForce = 0.f; } 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); } void DrawNode(iCameraPane display, Object3D /*Composite*/ root, boolean selected) // ?? { // super.DrawNode(display,root,selected); renderme(display); if (Globals.isLIVE()) // && display.drawMode != display.SHADOW) { float ms = getDeltaTimeMicroseconds(); float minFPS = 1000000f / 60f; if (ms > minFPS) { ms = minFPS; } if (CameraPane.AntialiasingEnabled()) ms /= CameraPane.ACSIZE; // totalms += ms; // // if (totalms > 2000000) // { // spawnRagdoll(true); // totalms = 0; // } dynamicsWorld.stepSimulation(ms / 1000000.f); } } private final Transform m = new Transform(); private Vector3f wireColor = new Vector3f(); // protected Color3f TEXT_COLOR = new Color3f(0f, 0f, 0f); private StringBuilder buf = new StringBuilder(); protected int debugMode = 0; public int getDebugMode() { return debugMode; } public void renderme0(iCameraPane display) { //updateCamera(); GL gl = display.GetGL0(); if (dynamicsWorld != null) { int numObjects = dynamicsWorld.getNumCollisionObjects(); wireColor.set(1f, 0f, 0f); for (int i = 0; i < numObjects; i++) { CollisionObject colObj = dynamicsWorld.getCollisionObjectArray().getQuick(i); RigidBody body = RigidBody.upcast(colObj); if (body != null && body.getMotionState() != null) { DefaultMotionState myMotionState = (DefaultMotionState) body.getMotionState(); m.set(myMotionState.graphicsWorldTrans); } else { colObj.getWorldTransform(m); } wireColor.set(1f, 1f, 0.5f); // wants deactivation if ((i & 1) != 0) { wireColor.set(0f, 0f, 1f); } // color differently for active, sleeping, wantsdeactivation states if (colObj.getActivationState() == 1) // active { if ((i & 1) != 0) { //wireColor.add(new Vector3f(1f, 0f, 0f)); wireColor.x += 1f; } else { //wireColor.add(new Vector3f(0.5f, 0f, 0f)); wireColor.x += 0.5f; } } if (colObj.getActivationState() == 2) // ISLAND_SLEEPING { if ((i & 1) != 0) { //wireColor.add(new Vector3f(0f, 1f, 0f)); wireColor.y += 1f; } else { //wireColor.add(new Vector3f(0f, 0.5f, 0f)); wireColor.y += 0.5f; } } GLShapeDrawer.drawOpenGL(display, m, colObj.getCollisionShape(), wireColor, getDebugMode()); } float xOffset = 10f; float yStart = 20f; float yIncr = 20f; gl.glDisable(gl.GL_LIGHTING); gl.glColor3f(0f, 0f, 0f); // if ((debugMode & DebugDrawModes.NO_HELP_TEXT) == 0) { // setOrthographicProjection(); // // yStart = showProfileInfo(xOffset, yStart, yIncr); // //// #ifdef USE_QUICKPROF //// if ( getDebugMode() & btIDebugDraw::DBG_ProfileTimings) //// { //// static int counter = 0; //// counter++; //// std::map::iterator iter; //// for (iter = btProfiler::mProfileBlocks.begin(); iter != btProfiler::mProfileBlocks.end(); ++iter) //// { //// char blockTime[128]; //// sprintf(blockTime, "%s: %lf",&((*iter).first[0]),btProfiler::getBlockTime((*iter).first, btProfiler::BLOCK_CYCLE_SECONDS));//BLOCK_TOTAL_PERCENT)); //// glRasterPos3f(xOffset,yStart,0); //// BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),blockTime); //// yStart += yIncr; //// //// } //// } //// #endif //USE_QUICKPROF // // // String s = "mouse to interact"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // // JAVA NOTE: added // s = "LMB=drag, RMB=shoot box, MIDDLE=apply impulse"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "space to reset"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "cursor keys and z,x to navigate"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "i to toggle simulation, s single step"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "q to quit"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = ". to shoot box or trimesh (MovingConcaveDemo)"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // // not yet hooked up again after refactoring... // // s = "d to toggle deactivation"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "g to toggle mesh animation (ConcaveDemo)"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // // JAVA NOTE: added // s = "e to spawn new body (GenericJointDemo)"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // s = "h to toggle help text"; // drawString(s, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // //buf = "p to toggle profiling (+results to file)"; // //drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // //bool useBulletLCP = !(getDebugMode() & btIDebugDraw::DBG_DisableBulletLCP); // //bool useCCD = (getDebugMode() & btIDebugDraw::DBG_EnableCCD); // //glRasterPos3f(xOffset,yStart,0); // //sprintf(buf,"1 CCD mode (adhoc) = %i",useCCD); // //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); // //yStart += yIncr; // // //glRasterPos3f(xOffset, yStart, 0); // //buf = String.format(%10.2f", ShootBoxInitialSpeed); // buf.setLength(0); // buf.append("+- shooting speed = "); // FastFormat.append(buf, ShootBoxInitialSpeed); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // //#ifdef SHOW_NUM_DEEP_PENETRATIONS // buf.setLength(0); // buf.append("gNumDeepPenetrationChecks = "); // FastFormat.append(buf, BulletStats.gNumDeepPenetrationChecks); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // buf.setLength(0); // buf.append("gNumGjkChecks = "); // FastFormat.append(buf, BulletStats.gNumGjkChecks); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // buf.setLength(0); // buf.append("gNumSplitImpulseRecoveries = "); // FastFormat.append(buf, BulletStats.gNumSplitImpulseRecoveries); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // //buf = String.format("gNumAlignedAllocs = %d", BulletGlobals.gNumAlignedAllocs); // // TODO: BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); // //yStart += yIncr; // // //buf = String.format("gNumAlignedFree= %d", BulletGlobals.gNumAlignedFree); // // TODO: BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); // //yStart += yIncr; // // //buf = String.format("# alloc-free = %d", BulletGlobals.gNumAlignedAllocs - BulletGlobals.gNumAlignedFree); // // TODO: BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); // //yStart += yIncr; // // //enable BT_DEBUG_MEMORY_ALLOCATIONS define in Bullet/src/LinearMath/btAlignedAllocator.h for memory leak detection // //#ifdef BT_DEBUG_MEMORY_ALLOCATIONS // //glRasterPos3f(xOffset,yStart,0); // //sprintf(buf,"gTotalBytesAlignedAllocs = %d",gTotalBytesAlignedAllocs); // //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); // //yStart += yIncr; // //#endif //BT_DEBUG_MEMORY_ALLOCATIONS // // if (getDynamicsWorld() != null) { // buf.setLength(0); // buf.append("# objects = "); // FastFormat.append(buf, getDynamicsWorld().getNumCollisionObjects()); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // buf.setLength(0); // buf.append("# pairs = "); // FastFormat.append(buf, getDynamicsWorld().getBroadphase().getOverlappingPairCache().getNumOverlappingPairs()); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // } // //#endif //SHOW_NUM_DEEP_PENETRATIONS // // // JAVA NOTE: added // int free = (int)Runtime.getRuntime().freeMemory(); // int total = (int)Runtime.getRuntime().totalMemory(); // buf.setLength(0); // buf.append("heap = "); // FastFormat.append(buf, (float)(total - free) / (1024*1024)); // buf.append(" / "); // FastFormat.append(buf, (float)(total) / (1024*1024)); // buf.append(" MB"); // drawString(buf, Math.round(xOffset), Math.round(yStart), TEXT_COLOR); // yStart += yIncr; // // resetPerspectiveProjection(); // } gl.glEnable(gl.GL_LIGHTING); } // updateCamera(); } // // to be implemented by the demo // @Override public void renderme(iCameraPane display) { // updateCamera(); CylinderShapeX wheelShape = new CylinderShapeX(new Vector3f(wheelWidth, wheelRadius, wheelRadius)); Vector3f wheelColor = new Vector3f(1, 0, 0); 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(display, trans, wheelShape, wheelColor, getDebugMode()); } renderme0(display); } static protected Clock clock = new Clock(); static public float getDeltaTimeMicroseconds() { //#ifdef USE_BT_CLOCK float dt = clock.getTimeMicroseconds(); clock.reset(); return dt; //#else //return btScalar(16666.); //#endif } // // @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 displayCallback() { // gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); // // renderme(); // // // optional but useful: debug drawing // if (dynamicsWorld != null) { // dynamicsWorld.debugDrawWorld(); // } // } // // @Override public void clientResetScene() { gVehicleSteering = 0f; 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(), dynamicsWorld.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); } } } // // @Override // public void specialKeyboardUp(int key, int x, int y, int modifiers) { // switch (key) { // case Keyboard.KEY_UP: { // gEngineForce = 0f; // break; // } // case Keyboard.KEY_DOWN: { // gBreakingForce = 0f; // break; // } // default: // super.specialKeyboardUp(key, x, y, modifiers); // break; // } // } // // @Override // public void specialKeyboard(int key, int x, int y, int modifiers) { // // printf("key = %i x=%i y=%i\n",key,x,y); // // 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: { // gBreakingForce = maxBreakingForce; // gEngineForce = 0.f; // break; // } // default: // super.specialKeyboard(key, x, y, modifiers); // break; // } // // //glutPostRedisplay(); // } // // @Override // public void updateCamera() // { // // // //#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); // } // // public static void main(String[] args) throws LWJGLException { // VehicleDemo vehicleDemo = new VehicleDemo(LWJGL.getGL()); // vehicleDemo.initPhysics(); // vehicleDemo.getDynamicsWorld().setDebugDrawer(new GLDebugDrawer(LWJGL.getGL())); // // LWJGL.main(args, 800, 600, "Bullet Vehicle Demo", vehicleDemo); // } }