/*
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
*
* 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 javabullet.demos.opengl;
import javabullet.BulletStack;
import javabullet.collision.broadphase.BroadphaseNativeType;
import javabullet.collision.shapes.BoxShape;
import javabullet.collision.shapes.CapsuleShape;
import javabullet.collision.shapes.CollisionShape;
import javabullet.collision.shapes.CompoundShape;
import javabullet.collision.shapes.ConcaveShape;
import javabullet.collision.shapes.CylinderShape;
import javabullet.collision.shapes.InternalTriangleIndexCallback;
import javabullet.collision.shapes.PolyhedralConvexShape;
import javabullet.collision.shapes.SphereShape;
import javabullet.collision.shapes.TriangleCallback;
import javabullet.linearmath.DebugDrawModes;
import javabullet.linearmath.Transform;
import javabullet.linearmath.VectorUtil;
import javax.vecmath.Vector3f;
import com.jogamp.opengl.*;
import com.jogamp.opengl.util.ImmModeSink;
/**
*
* @author jezek2
*/
public class GLShapeDrawer {
/*
private static Map<CollisionShape,TriMeshKey> g_display_lists = new HashMap<CollisionShape,TriMeshKey>();
private static int OGL_get_displaylist_for_shape(CollisionShape shape) {
// JAVA NOTE: rewritten
TriMeshKey trimesh = g_display_lists.get(shape);
if (trimesh != null) {
return trimesh.dlist;
}
return 0;
}
private static void OGL_displaylist_clean() {
// JAVA NOTE: rewritten
for (TriMeshKey trimesh : g_display_lists.values()) {
glDeleteLists(trimesh.dlist, 1);
}
g_display_lists.clear();
}
*/
public static void drawCoordSystem(GL gl) {
ImmModeSink vbo = ImmModeSink.createFixed(GL.GL_STATIC_DRAW, 10,
3, GL.GL_FLOAT, // vertex
4, GL.GL_FLOAT, // color
0, GL.GL_FLOAT, // normal
0, GL.GL_FLOAT); // texture
vbo.glBegin(gl.GL_LINES);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 0f, 0f, 0f);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 1f, 0f, 0f);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 0f, 0f, 0f);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 0f, 1f, 0f);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 0f, 0f, 0f);
vbo.glColor4f ( 1f, 1f, 1f, 1f);
vbo.glVertex3f( 0f, 0f, 1f);
vbo.glEnd(gl);
}
private static float[] glMat = new float[16];
public static void drawOpenGL(GLSRT glsrt, GL gl, Transform trans, CollisionShape shape, Vector3f color, int debugMode) {
BulletStack stack = BulletStack.get();
stack.pushCommonMath();
try {
//System.out.println("shape="+shape+" type="+BroadphaseNativeTypes.forValue(shape.getShapeType()));
gl.glPushMatrix();
trans.getOpenGLMatrix(glMat);
gl.glMultMatrixf(glMat, 0);
// if (shape.getShapeType() == BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE.getValue())
// {
// const btUniformScalingShape* scalingShape = static_cast<const btUniformScalingShape*>(shape);
// const btConvexShape* convexShape = scalingShape->getChildShape();
// float scalingFactor = (float)scalingShape->getUniformScalingFactor();
// {
// btScalar tmpScaling[4][4]={{scalingFactor,0,0,0},
// {0,scalingFactor,0,0},
// {0,0,scalingFactor,0},
// {0,0,0,1}};
//
// drawOpenGL( (btScalar*)tmpScaling,convexShape,color,debugMode);
// }
// return;
// }
if (shape.getShapeType() == BroadphaseNativeType.COMPOUND_SHAPE_PROXYTYPE) {
CompoundShape compoundShape = (CompoundShape) shape;
for (int i = compoundShape.getNumChildShapes() - 1; i >= 0; i--) {
Transform childTrans = stack.transforms.get(compoundShape.getChildTransform(i));
CollisionShape colShape = compoundShape.getChildShape(i);
drawOpenGL(glsrt, gl, childTrans, colShape, color, debugMode);
}
}
else {
gl.glEnable(gl.GL_COLOR_MATERIAL);
gl.glColor4f(color.x, color.y, color.z, 1f);
boolean useWireframeFallback = true;
if ( (debugMode & DebugDrawModes.DRAW_WIREFRAME) == 0) {
switch (shape.getShapeType()) {
case BOX_SHAPE_PROXYTYPE: {
BoxShape boxShape = (BoxShape) shape;
Vector3f halfExtent = stack.vectors.get(boxShape.getHalfExtentsWithMargin());
gl.glScalef(2f * halfExtent.x, 2f * halfExtent.y, 2f * halfExtent.z);
glsrt.drawCube(gl, 1f);
useWireframeFallback = false;
break;
}
case TRIANGLE_SHAPE_PROXYTYPE:
case TETRAHEDRAL_SHAPE_PROXYTYPE: {
//todo:
// useWireframeFallback = false;
break;
}
case CONVEX_HULL_SHAPE_PROXYTYPE:
break;
case SPHERE_SHAPE_PROXYTYPE: {
SphereShape sphereShape = (SphereShape) shape;
float radius = sphereShape.getMargin(); // radius doesn't include the margin, so draw with margin
// TODO: glutSolidSphere(radius,10,10);
//sphere.draw(radius, 8, 8);
glsrt.drawSphere(gl, radius, 10, 10);
/*
glPointSize(10f);
glBegin(gl.GL_POINTS);
glVertex3f(0f, 0f, 0f);
glEnd();
glPointSize(1f);
*/
useWireframeFallback = false;
break;
}
case CAPSULE_SHAPE_PROXYTYPE:
{
CapsuleShape capsuleShape = (CapsuleShape)shape;
float radius = capsuleShape.getRadius();
float halfHeight = capsuleShape.getHalfHeight();
int upAxis = 1;
glsrt.drawCylinder(gl, radius,halfHeight,upAxis);
gl.glTranslatef(0f, -halfHeight, 0f);
//glutSolidSphere(radius,10,10);
//sphere.draw(radius, 10, 10);
glsrt.drawSphere(gl, radius, 10, 10);
gl.glTranslatef(0f, 2f*halfHeight,0f);
//glutSolidSphere(radius,10,10);
//sphere.draw(radius, 10, 10);
glsrt.drawSphere(gl, radius, 10, 10);
useWireframeFallback = false;
break;
}
case MULTI_SPHERE_SHAPE_PROXYTYPE: {
break;
}
// case CONE_SHAPE_PROXYTYPE:
// {
// const btConeShape* coneShape = static_cast<const btConeShape*>(shape);
// int upIndex = coneShape->getConeUpIndex();
// float radius = coneShape->getRadius();//+coneShape->getMargin();
// float height = coneShape->getHeight();//+coneShape->getMargin();
// switch (upIndex)
// {
// case 0:
// glRotatef(90.0, 0.0, 1.0, 0.0);
// break;
// case 1:
// glRotatef(-90.0, 1.0, 0.0, 0.0);
// break;
// case 2:
// break;
// default:
// {
// }
// };
//
// glTranslatef(0.0, 0.0, -0.5*height);
// glutSolidCone(radius,height,10,10);
// useWireframeFallback = false;
// break;
//
// }
case CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: {
useWireframeFallback = false;
break;
}
case CONVEX_SHAPE_PROXYTYPE:
case CYLINDER_SHAPE_PROXYTYPE:
{
CylinderShape cylinder = (CylinderShape) shape;
int upAxis = cylinder.getUpAxis();
float radius = cylinder.getRadius();
float halfHeight = VectorUtil.getCoord(cylinder.getHalfExtentsWithMargin(), upAxis);
glsrt.drawCylinder(gl, radius, halfHeight, upAxis);
break;
}
default: {
}
}
}
if (useWireframeFallback) {
// for polyhedral shapes
if (shape.isPolyhedral()) {
PolyhedralConvexShape polyshape = (PolyhedralConvexShape) shape;
ImmModeSink vbo = ImmModeSink.createFixed(GL.GL_STATIC_DRAW, polyshape.getNumEdges()+3,
3, GL.GL_FLOAT, // vertex
0, GL.GL_FLOAT, // color
0, GL.GL_FLOAT, // normal
0, GL.GL_FLOAT); // texture
vbo.glBegin(gl.GL_LINES);
Vector3f a = stack.vectors.get(), b = stack.vectors.get();
int i;
for (i = 0; i < polyshape.getNumEdges(); i++) {
polyshape.getEdge(i, a, b);
vbo.glVertex3f(a.x, a.y, a.z);
vbo.glVertex3f(b.x, b.y, b.z);
}
vbo.glEnd(gl);
// if (debugMode==btIDebugDraw::DBG_DrawFeaturesText)
// {
// glRasterPos3f(0.0, 0.0, 0.0);
// //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),polyshape->getExtraDebugInfo());
//
// glColor3f(1.f, 1.f, 1.f);
// for (i=0;i<polyshape->getNumVertices();i++)
// {
// btPoint3 vtx;
// polyshape->getVertex(i,vtx);
// glRasterPos3f(vtx.x(), vtx.y(), vtx.z());
// char buf[12];
// sprintf(buf," %d",i);
// BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
// }
//
// for (i=0;i<polyshape->getNumPlanes();i++)
// {
// btVector3 normal;
// btPoint3 vtx;
// polyshape->getPlane(normal,vtx,i);
// btScalar d = vtx.dot(normal);
//
// glRasterPos3f(normal.x()*d, normal.y()*d, normal.z()*d);
// char buf[12];
// sprintf(buf," plane %d",i);
// BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf);
//
// }
// }
}
}
// #ifdef USE_DISPLAY_LISTS
//
// if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE||shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE)
// {
// GLuint dlist = OGL_get_displaylist_for_shape((btCollisionShape * )shape);
// if (dlist)
// {
// glCallList(dlist);
// }
// else
// {
// #else
if (shape.isConcave())//>getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE||shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE)
// if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
{
ConcaveShape concaveMesh = (ConcaveShape) shape;
//btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30));
//btVector3 aabbMax(100,100,100);//btScalar(1e30),btScalar(1e30),btScalar(1e30));
//todo pass camera, for some culling
Vector3f aabbMax = stack.vectors.get(1e30f, 1e30f, 1e30f);
Vector3f aabbMin = stack.vectors.get(-1e30f, -1e30f, -1e30f);
GlDrawcallback drawCallback = new GlDrawcallback(gl);
drawCallback.wireframe = (debugMode & DebugDrawModes.DRAW_WIREFRAME) != 0;
concaveMesh.processAllTriangles(drawCallback, aabbMin, aabbMax);
}
//#endif
//#ifdef USE_DISPLAY_LISTS
// }
// }
//#endif
// 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));
// TriangleGlDrawcallback drawCallback;
// convexMesh->getMeshInterface()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax);
//
// }
// TODO: error in original sources GL_DEPTH_BUFFER_BIT instead of GL_DEPTH_TEST
//gl.glDisable(GL_DEPTH_TEST);
//glRasterPos3f(0, 0, 0);//mvtx.x(), vtx.y(), vtx.z());
if ((debugMode & DebugDrawModes.DRAW_TEXT) != 0) {
// TODO: BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),shape->getName());
}
if ((debugMode & DebugDrawModes.DRAW_FEATURES_TEXT) != 0) {
//BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),shape->getExtraDebugInfo());
}
//gl.glEnable(GL_DEPTH_TEST);
}
}
finally {
gl.glPopMatrix();
stack.popCommonMath();
}
}
////////////////////////////////////////////////////////////////////////////
private static class TriMeshKey {
public CollisionShape shape;
public int dlist; // OpenGL display list
}
private static class GlDisplaylistDrawcallback implements TriangleCallback {
private GL gl;
private final Vector3f diff1 = new Vector3f();
private final Vector3f diff2 = new Vector3f();
private final Vector3f normal = new Vector3f();
public GlDisplaylistDrawcallback(GL gl) {
this.gl = gl;
}
public void processTriangle(Vector3f[] triangle, int partId, int triangleIndex) {
diff1.sub(triangle[1], triangle[0]);
diff2.sub(triangle[2], triangle[0]);
normal.cross(diff1, diff2);
normal.normalize();
ImmModeSink vbo = ImmModeSink.createFixed(GL.GL_STATIC_DRAW, 3,
3, GL.GL_FLOAT, // vertex
4, GL.GL_FLOAT, // color
3, GL.GL_FLOAT, // normal
0, GL.GL_FLOAT); // texture
vbo.glBegin(gl.GL_TRIANGLES);
vbo.glColor4f(0, 1f, 0, 1f);
vbo.glNormal3f(normal.x, normal.y, normal.z);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glColor4f(0, 1f, 0, 1f);
vbo.glNormal3f(normal.x, normal.y, normal.z);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 1f, 0, 1f);
vbo.glNormal3f(normal.x, normal.y, normal.z);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glEnd(gl);
/*glBegin(gl.GL_LINES);
glColor3f(1, 1, 0);
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ());
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ());
glColor3f(1, 1, 0);
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ());
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ());
glColor3f(1, 1, 0);
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ());
glNormal3d(normal.getX(),normal.getY(),normal.getZ());
glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ());
glEnd();*/
}
}
private static class GlDrawcallback implements TriangleCallback {
private GL gl;
public boolean wireframe = false;
public GlDrawcallback(GL gl) {
this.gl = gl;
}
public void processTriangle(Vector3f[] triangle, int partId, int triangleIndex) {
ImmModeSink vbo = ImmModeSink.createFixed(GL.GL_STATIC_DRAW, 10,
3, GL.GL_FLOAT, // vertex
4, GL.GL_FLOAT, // color
0, GL.GL_FLOAT, // normal
0, GL.GL_FLOAT); // texture
if (wireframe) {
vbo.glBegin(gl.GL_LINES);
vbo.glColor4f(1, 0, 0, 1);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 1, 0, 1);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 0, 1, 1);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glEnd(gl);
}
else {
vbo.glBegin(gl.GL_TRIANGLES);
vbo.glColor4f(1, 0, 0, 1);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glColor4f(0, 1, 0, 1);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 0, 1, 1);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glEnd(gl);
}
}
}
private static class TriangleGlDrawcallback implements InternalTriangleIndexCallback {
private GL gl;
public TriangleGlDrawcallback(GL gl) {
this.gl = gl;
}
public void internalProcessTriangleIndex(Vector3f[] triangle, int partId, int triangleIndex) {
ImmModeSink vbo = ImmModeSink.createFixed(GL.GL_STATIC_DRAW, 10,
3, GL.GL_FLOAT, // vertex
4, GL.GL_FLOAT, // color
0, GL.GL_FLOAT, // normal
0, GL.GL_FLOAT); // texture
vbo.glBegin(gl.GL_TRIANGLES);//LINES);
vbo.glColor4f(1, 0, 0, 1);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 1, 0, 1);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glVertex3f(triangle[1].x, triangle[1].y, triangle[1].z);
vbo.glColor4f(0, 0, 1, 1);
vbo.glVertex3f(triangle[2].x, triangle[2].y, triangle[2].z);
vbo.glVertex3f(triangle[0].x, triangle[0].y, triangle[0].z);
vbo.glEnd(gl);
}
}
}