package net.sf.openrocket.gui.figure3d.geometry;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;
import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.MassObject;
import net.sf.openrocket.rocketcomponent.RingComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.rocketcomponent.Transition.Shape;
import net.sf.openrocket.rocketcomponent.TubeFinSet;
import net.sf.openrocket.util.Coordinate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* @author Bill Kuker <bkuker@billkuker.com>
*/
public class ComponentRenderer {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(ComponentRenderer.class);
private int LOD = 80;
GLU glu;
GLUquadric q;
FinRenderer fr = new FinRenderer();
public ComponentRenderer() {
}
public void init(GLAutoDrawable drawable) {
glu = new GLU();
q = glu.gluNewQuadric();
glu.gluQuadricTexture(q, true);
}
public void updateFigure(GLAutoDrawable drawable) {
}
public Geometry getGeometry(final RocketComponent c, final Surface which) {
return new Geometry() {
@Override
public void render(GL2 gl) {
if (which == Surface.ALL) {
renderGeometry(gl, c, Surface.INSIDE);
renderGeometry(gl, c, Surface.EDGES);
renderGeometry(gl, c, Surface.OUTSIDE);
} else {
renderGeometry(gl, c, which);
}
}
};
}
public Geometry getGeometry(final Motor motor, Surface which) {
return new Geometry() {
@Override
public void render(GL2 gl) {
renderMotor(gl, motor);
}
};
}
protected void renderGeometry(GL2 gl, RocketComponent c, Surface which) {
if (glu == null)
throw new IllegalStateException(this + " Not Initialized");
glu.gluQuadricNormals(q, GLU.GLU_SMOOTH);
Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0));
for (Coordinate o : oo) {
gl.glPushMatrix();
gl.glTranslated(o.x, o.y, o.z);
if (c instanceof BodyTube) {
renderTube(gl, (BodyTube) c, which);
} else if (c instanceof LaunchLug) {
renderLug(gl, (LaunchLug) c, which);
} else if (c instanceof RingComponent) {
if (which == Surface.OUTSIDE)
renderRing(gl, (RingComponent) c);
} else if (c instanceof Transition) {
renderTransition(gl, (Transition) c, which);
} else if (c instanceof MassObject) {
if (which == Surface.OUTSIDE)
renderMassObject(gl, (MassObject) c);
} else if (c instanceof FinSet) {
if (which == Surface.OUTSIDE)
fr.renderFinSet(gl, (FinSet) c);
} else if (c instanceof TubeFinSet) {
renderTubeFins( gl, (TubeFinSet) c, which);
} else {
renderOther(gl, c);
}
gl.glPopMatrix();
}
}
private void renderOther(GL2 gl, RocketComponent c) {
gl.glBegin(GL.GL_LINES);
for (Coordinate cc : c.getComponentBounds()) {
for (Coordinate ccc : c.getComponentBounds()) {
gl.glVertex3d(cc.x, cc.y, cc.z);
gl.glVertex3d(ccc.x, ccc.y, ccc.z);
}
}
gl.glEnd();
}
private void renderTransition(GL2 gl, Transition t, Surface which) {
if (which == Surface.OUTSIDE || which == Surface.INSIDE) {
gl.glPushMatrix();
gl.glRotated(90, 0, 1.0, 0);
if (which == Surface.INSIDE) {
gl.glFrontFace(GL.GL_CCW);
}
TransitionRenderer.drawTransition(gl, t, LOD, t.getType() == Shape.CONICAL ? 4 : LOD / 2, which == Surface.INSIDE ? -t.getThickness() : 0);
if (which == Surface.INSIDE) {
gl.glFrontFace(GL.GL_CW);
}
gl.glPopMatrix();
}
if (which == Surface.EDGES || which == Surface.INSIDE) {
//Render aft edge
gl.glPushMatrix();
gl.glTranslated(t.getLength(), 0, 0);
if (which == Surface.EDGES) {
gl.glRotated(90, 0, 1.0, 0);
glu.gluDisk(q, Math.max(0, t.getAftRadius() - t.getThickness()), t.getAftRadius(), LOD, 2);
} else {
gl.glRotated(270, 0, 1.0, 0);
glu.gluDisk(q, Math.max(0, t.getAftRadius() - t.getThickness()), t.getAftRadius(), LOD, 2);
}
gl.glPopMatrix();
// Render AFT shoulder
if (t.getAftShoulderLength() > 0) {
gl.glPushMatrix();
gl.glTranslated(t.getLength(), 0, 0);
double iR = (t.isFilled() || t.isAftShoulderCapped()) ? 0 : t.getAftShoulderRadius() - t.getAftShoulderThickness();
if (which == Surface.EDGES) {
renderTube(gl, Surface.OUTSIDE, t.getAftShoulderRadius(), iR, t.getAftShoulderLength());
renderTube(gl, Surface.EDGES, t.getAftShoulderRadius(), iR, t.getAftShoulderLength());
gl.glPushMatrix();
gl.glRotated(90, 0, 1.0, 0);
glu.gluDisk(q, t.getAftShoulderRadius(), t.getAftRadius(), LOD, 2);
gl.glPopMatrix();
} else {
renderTube(gl, Surface.INSIDE, t.getAftShoulderRadius(), iR, t.getAftShoulderLength());
gl.glPushMatrix();
gl.glRotated(270, 0, 1.0, 0);
glu.gluDisk(q, t.getAftShoulderRadius(), t.getAftRadius(), LOD, 2);
gl.glPopMatrix();
}
gl.glPopMatrix();
}
//Render Fore edge
gl.glPushMatrix();
gl.glRotated(180, 0, 1.0, 0);
if (which == Surface.EDGES) {
gl.glRotated(90, 0, 1.0, 0);
glu.gluDisk(q, Math.max(0, t.getForeRadius() - t.getThickness()), t.getForeRadius(), LOD, 2);
} else {
gl.glRotated(270, 0, 1.0, 0);
glu.gluDisk(q, Math.max(0, t.getForeRadius() - t.getThickness()), t.getForeRadius(), LOD, 2);
}
gl.glPopMatrix();
// Render Fore shoulder
if (t.getForeShoulderLength() > 0) {
gl.glPushMatrix();
gl.glRotated(180, 0, 1.0, 0);
//gl.glTranslated(t.getLength(), 0, 0);
double iR = (t.isFilled() || t.isForeShoulderCapped()) ? 0 : t.getForeShoulderRadius() - t.getForeShoulderThickness();
if (which == Surface.EDGES) {
renderTube(gl, Surface.OUTSIDE, t.getForeShoulderRadius(), iR, t.getForeShoulderLength());
renderTube(gl, Surface.EDGES, t.getForeShoulderRadius(), iR, t.getForeShoulderLength());
gl.glPushMatrix();
gl.glRotated(90, 0, 1.0, 0);
glu.gluDisk(q, t.getForeShoulderRadius(), t.getForeRadius(), LOD, 2);
gl.glPopMatrix();
} else {
renderTube(gl, Surface.INSIDE, t.getForeShoulderRadius(), iR, t.getForeShoulderLength());
gl.glPushMatrix();
gl.glRotated(270, 0, 1.0, 0);
glu.gluDisk(q, t.getForeShoulderRadius(), t.getForeRadius(), LOD, 2);
gl.glPopMatrix();
}
gl.glPopMatrix();
}
}
}
private void renderTube(final GL2 gl, final Surface which, final double oR, final double iR, final double len) {
gl.glPushMatrix();
//outside
gl.glRotated(90, 0, 1.0, 0);
if (which == Surface.OUTSIDE)
glu.gluCylinder(q, oR, oR, len, LOD, 1);
//edges
gl.glRotated(180, 0, 1.0, 0);
if (which == Surface.EDGES)
glu.gluDisk(q, iR, oR, LOD, 2);
gl.glRotated(180, 0, 1.0, 0);
gl.glTranslated(0, 0, len);
if (which == Surface.EDGES)
glu.gluDisk(q, iR, oR, LOD, 2);
//inside
if (which == Surface.INSIDE) {
glu.gluQuadricOrientation(q, GLU.GLU_INSIDE);
glu.gluCylinder(q, iR, iR, -len, LOD, 1);
glu.gluQuadricOrientation(q, GLU.GLU_OUTSIDE);
}
gl.glPopMatrix();
}
private void renderTube(GL2 gl, BodyTube t, Surface which) {
renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
}
private void renderRing(GL2 gl, RingComponent r) {
gl.glRotated(90, 0, 1.0, 0);
glu.gluCylinder(q, r.getOuterRadius(), r.getOuterRadius(),
r.getLength(), LOD, 1);
gl.glRotated(180, 0, 1.0, 0);
glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);
gl.glRotated(180, 0, 1.0, 0);
gl.glTranslated(0, 0, r.getLength());
glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);
glu.gluQuadricOrientation(q, GLU.GLU_INSIDE);
glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(),
-r.getLength(), LOD, 1);
glu.gluQuadricOrientation(q, GLU.GLU_OUTSIDE);
}
private void renderLug(GL2 gl, LaunchLug t, Surface which) {
renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
}
private void renderTubeFins(GL2 gl, TubeFinSet fs, Surface which) {
gl.glPushMatrix();
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
System.out.println(fs.getBaseRotation());
gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);
for( int i = 0; i< fs.getFinCount(); i++ ) {
gl.glPushMatrix();
gl.glTranslated(0, fs.getOuterRadius() + fs.getBodyRadius(), 0);
renderTube(gl, which, fs.getOuterRadius(), fs.getInnerRadius(), fs.getLength());
gl.glPopMatrix();
gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);
}
gl.glPopMatrix();
}
private void renderMassObject(GL2 gl, MassObject o) {
gl.glRotated(90, 0, 1.0, 0);
MassObjectRenderer.drawMassObject(gl, o, LOD / 2, LOD / 2);
}
private void renderMotor(final GL2 gl, Motor motor) {
double l = motor.getLength();
double r = motor.getDiameter() / 2;
gl.glPushMatrix();
gl.glRotated(90, 0, 1.0, 0);
gl.glMatrixMode(GL.GL_TEXTURE);
gl.glPushMatrix();
gl.glTranslated(0, .125, 0);
gl.glScaled(1, .75, 0);
glu.gluCylinder(q, r, r, l, LOD, 1);
gl.glPopMatrix();
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
{
final double da = (2.0f * Math.PI) / LOD;
final double dt = 1.0 / LOD;
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glNormal3d(0, 0, 1);
for (int i = 0; i < LOD + 1; i++) {
gl.glTexCoord2d(i * dt, .125);
gl.glVertex3d(r * Math.cos(da * i), r * Math.sin(da * i), 0);
gl.glTexCoord2d(i * dt, 0);
gl.glVertex3d(0, 0, 0);
}
gl.glEnd();
}
gl.glTranslated(0, 0, l);
gl.glRotated(180, 0, 1.0, 0);
{
final double da = (2.0f * Math.PI) / LOD;
final double dt = 1.0 / LOD;
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glNormal3d(0, 0, -1);
for (int i = 0; i < LOD + 1; i++) {
gl.glTexCoord2d(i * dt, .875);
gl.glVertex3d(r * Math.cos(da * i), r * Math.sin(da * i), 0);
gl.glTexCoord2d(i * dt, .9);
gl.glVertex3d(.8 * r * Math.cos(da * i), .8 * r * Math.sin(da * i), 0);
}
gl.glEnd();
gl.glBegin(GL.GL_TRIANGLE_STRIP);
for (int i = 0; i < LOD + 1; i++) {
gl.glNormal3d(-Math.cos(da * i), -Math.sin(da * i), -1);
gl.glTexCoord2d(i * dt, .9);
gl.glVertex3d(.8 * r * Math.cos(da * i), .8 * r * Math.sin(da * i), 0);
gl.glTexCoord2d(i * dt, 1);
gl.glVertex3d(0, 0, l * .05);
}
gl.glEnd();
}
gl.glPopMatrix();
}
}