1 package net.sf.openrocket.gui.figure3d;
\r
3 import java.util.HashMap;
\r
4 import java.util.Map;
\r
6 import javax.media.opengl.GL;
\r
7 import javax.media.opengl.GL2;
\r
8 import javax.media.opengl.GLAutoDrawable;
\r
9 import javax.media.opengl.fixedfunc.GLLightingFunc;
\r
10 import javax.media.opengl.fixedfunc.GLMatrixFunc;
\r
11 import javax.media.opengl.glu.GLU;
\r
12 import javax.media.opengl.glu.GLUquadric;
\r
13 import javax.media.opengl.glu.GLUtessellator;
\r
14 import javax.media.opengl.glu.GLUtessellatorCallback;
\r
15 import javax.media.opengl.glu.GLUtessellatorCallbackAdapter;
\r
17 import net.sf.openrocket.logging.LogHelper;
\r
18 import net.sf.openrocket.rocketcomponent.BodyTube;
\r
19 import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
\r
20 import net.sf.openrocket.rocketcomponent.FinSet;
\r
21 import net.sf.openrocket.rocketcomponent.LaunchLug;
\r
22 import net.sf.openrocket.rocketcomponent.MassObject;
\r
23 import net.sf.openrocket.rocketcomponent.RingComponent;
\r
24 import net.sf.openrocket.rocketcomponent.RocketComponent;
\r
25 import net.sf.openrocket.rocketcomponent.Transition;
\r
26 import net.sf.openrocket.startup.Application;
\r
27 import net.sf.openrocket.util.Coordinate;
\r
30 * @author Bill Kuker <bkuker@billkuker.com>
\r
32 public class ComponentRenderer {
\r
33 private static final LogHelper log = Application.getLogger();
\r
35 private int LOD = 80;
\r
39 GLUtessellator tobj;
\r
41 public ComponentRenderer() {
\r
45 public void init(GLAutoDrawable drawable) {
\r
47 q = glu.gluNewQuadric();
\r
48 tobj = GLU.gluNewTess();
\r
49 glu.gluQuadricTexture(q, true);
\r
52 private Map<RocketComponent, Integer> lists = new HashMap<RocketComponent, Integer>();
\r
53 private boolean clearDisplayLists = false;
\r
54 public void updateFigure() {
\r
55 clearDisplayLists = true;
\r
58 public void renderGeometry(GL2 gl, RocketComponent c) {
\r
60 throw new IllegalStateException(this + " Not Initialized");
\r
62 glu.gluQuadricNormals(q, GLU.GLU_SMOOTH);
\r
64 if ( clearDisplayLists ){
\r
65 log.debug("Clearing Display Lists");
\r
66 for ( int i : lists.values() ){
\r
67 gl.glDeleteLists(i,1);
\r
70 clearDisplayLists = false;
\r
72 if ( lists.containsKey(c) ){
\r
73 gl.glCallList(lists.get(c));
\r
75 int list = gl.glGenLists(1);
\r
76 gl.glNewList(list, GL2.GL_COMPILE_AND_EXECUTE);
\r
78 Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0));
\r
80 for (Coordinate o : oo) {
\r
83 gl.glTranslated(o.x, o.y, o.z);
\r
85 if (c instanceof BodyTube) {
\r
86 renderTube(gl, (BodyTube) c);
\r
87 } else if (c instanceof LaunchLug) {
\r
88 renderLug(gl, (LaunchLug) c);
\r
89 } else if (c instanceof RingComponent) {
\r
90 renderRing(gl, (RingComponent) c);
\r
91 } else if (c instanceof Transition) {
\r
92 renderTransition(gl, (Transition) c);
\r
93 } else if (c instanceof MassObject) {
\r
94 renderMassObject(gl, (MassObject) c);
\r
95 } else if (c instanceof FinSet) {
\r
96 renderFinSet(gl, (FinSet) c);
\r
104 lists.put(c, list);
\r
108 private void renderOther(GL2 gl, RocketComponent c) {
\r
109 gl.glBegin(GL.GL_LINES);
\r
110 for (Coordinate cc : c.getComponentBounds()) {
\r
111 for (Coordinate ccc : c.getComponentBounds()) {
\r
112 gl.glVertex3d(cc.x, cc.y, cc.z);
\r
113 gl.glVertex3d(ccc.x, ccc.y, ccc.z);
\r
119 private void renderTransition(GL2 gl, Transition t) {
\r
120 gl.glRotated(90, 0, 1.0, 0);
\r
122 if (t.getType() == Transition.Shape.CONICAL) {
\r
123 glu.gluCylinder(q, t.getForeRadius(), t.getAftRadius(),
\r
124 t.getLength(), LOD, 1);
\r
126 TransitionRenderer.drawTransition(gl, t, LOD, LOD);
\r
129 // Render AFT shoulder
\r
131 gl.glTranslated(0, 0, t.getLength());
\r
133 glu.gluCylinder(q, t.getAftShoulderRadius(), t.getAftShoulderRadius(),
\r
134 t.getAftShoulderLength(), LOD, 1);
\r
136 gl.glRotated(180, 0, 1.0, 0);
\r
138 glu.gluDisk(q, t.getAftRadius(), t.getAftShoulderRadius(), LOD, 2);
\r
140 gl.glTranslated(0, 0, -t.getAftShoulderLength());
\r
142 if (t.isFilled() || t.isAftShoulderCapped()) {
\r
143 glu.gluDisk(q, t.getAftShoulderRadius(), 0, LOD, 2);
\r
147 // Render Fore Shoulder
\r
149 gl.glRotated(180, 0, 1.0, 0);
\r
151 glu.gluCylinder(q, t.getForeShoulderRadius(),
\r
152 t.getForeShoulderRadius(), t.getForeShoulderLength(), LOD, 1);
\r
154 gl.glRotated(180, 0, 1.0, 0);
\r
156 glu.gluDisk(q, t.getForeRadius(), t.getForeShoulderRadius(), LOD, 2);
\r
158 gl.glTranslated(0, 0, -t.getForeShoulderLength());
\r
160 if (t.isFilled() || t.isForeShoulderCapped()) {
\r
161 glu.gluDisk(q, t.getForeShoulderRadius(), 0, LOD, 2);
\r
167 private void renderTube(GL2 gl, BodyTube t) {
\r
168 gl.glRotated(90, 0, 1.0, 0);
\r
169 glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),
\r
170 t.getLength(), LOD, 1);
\r
173 private void renderRing(GL2 gl, RingComponent r) {
\r
174 gl.glRotated(90, 0, 1.0, 0);
\r
175 glu.gluCylinder(q, r.getOuterRadius(), r.getOuterRadius(),
\r
176 r.getLength(), LOD, 1);
\r
178 gl.glRotated(180, 0, 1.0, 0);
\r
179 glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);
\r
181 gl.glRotated(180, 0, 1.0, 0);
\r
182 gl.glTranslated(0, 0, r.getLength());
\r
183 glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);
\r
185 gl.glTranslated(0, 0, -r.getLength());
\r
186 glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(),
\r
187 r.getLength(), LOD, 1);
\r
191 private void renderLug(GL2 gl, LaunchLug t) {
\r
193 gl.glRotated(90, 0, 1.0, 0);
\r
194 glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),
\r
195 t.getLength(), LOD, 1);
\r
198 private void renderMassObject(GL2 gl, MassObject o) {
\r
199 gl.glRotated(90, 0, 1.0, 0);
\r
201 MassObjectRenderer.drawMassObject(gl, o, LOD, LOD);
\r
204 private void renderFinSet(final GL2 gl, FinSet fs) {
\r
206 Coordinate finPoints[] = fs.getFinPointsWithTab();
\r
208 double minX = Double.MAX_VALUE;
\r
209 double minY = Double.MAX_VALUE;
\r
210 double maxX = Double.MIN_VALUE;
\r
211 double maxY = Double.MIN_VALUE;
\r
213 for (int i = 0; i < finPoints.length; i++) {
\r
214 Coordinate c = finPoints[i];
\r
215 minX = Math.min(c.x, minX);
\r
216 minY = Math.min(c.y, minY);
\r
217 maxX = Math.max(c.x, maxX);
\r
218 maxY = Math.max(c.y, maxY);
\r
221 gl.glMatrixMode(GL.GL_TEXTURE);
\r
223 gl.glScaled(1/(maxX-minX), 1/(maxY-minY), 0);
\r
224 gl.glTranslated(-minX, -minY - fs.getBodyRadius(), 0);
\r
225 gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
\r
227 gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);
\r
229 for (int fin = 0; fin < fs.getFinCount(); fin++) {
\r
233 gl.glTranslated(fs.getLength() / 2, 0, 0);
\r
234 gl.glRotated(fs.getCantAngle() * (180.0 / Math.PI), 0, 1, 0);
\r
235 gl.glTranslated(-fs.getLength() / 2, 0, 0);
\r
237 GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {
\r
239 public void vertex(Object vertexData) {
\r
240 double d[] = (double[]) vertexData;
\r
241 gl.glTexCoord2d(d[0], d[1]);
\r
242 gl.glVertex3dv(d, 0);
\r
246 public void begin(int type) {
\r
251 public void end() {
\r
256 GLU.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, cb);
\r
257 GLU.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, cb);
\r
258 GLU.gluTessCallback(tobj, GLU.GLU_TESS_END, cb);
\r
260 GLU.gluTessBeginPolygon(tobj, null);
\r
261 GLU.gluTessBeginContour(tobj);
\r
262 gl.glNormal3f(0, 0, 1);
\r
263 for (int i = finPoints.length - 1; i >= 0; i--) {
\r
264 Coordinate c = finPoints[i];
\r
265 double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),
\r
266 c.z + fs.getThickness() / 2.0 };
\r
267 GLU.gluTessVertex(tobj, p, 0, p);
\r
270 GLU.gluTessEndContour(tobj);
\r
271 GLU.gluTessEndPolygon(tobj);
\r
273 GLU.gluTessBeginPolygon(tobj, null);
\r
274 GLU.gluTessBeginContour(tobj);
\r
275 gl.glNormal3f(0, 0, -1);
\r
276 for (int i = 0; i < finPoints.length; i++) {
\r
277 Coordinate c = finPoints[i];
\r
278 double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),
\r
279 c.z - fs.getThickness() / 2.0 };
\r
280 GLU.gluTessVertex(tobj, p, 0, p);
\r
283 GLU.gluTessEndContour(tobj);
\r
284 GLU.gluTessEndPolygon(tobj);
\r
286 // Strip around the edge
\r
287 if (!(fs instanceof EllipticalFinSet))
\r
288 gl.glShadeModel(GLLightingFunc.GL_FLAT);
\r
289 gl.glBegin(GL.GL_TRIANGLE_STRIP);
\r
290 for (int i = 0; i <= finPoints.length; i++) {
\r
291 Coordinate c = finPoints[i % finPoints.length];
\r
293 Coordinate c2 = finPoints[(i - 1 + finPoints.length)
\r
294 % finPoints.length];
\r
295 gl.glNormal3d(c2.y - c.y, c.x - c2.x, 0);
\r
297 gl.glTexCoord2d(c.x, c.y + fs.getBodyRadius());
\r
298 gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),
\r
299 c.z - fs.getThickness() / 2.0);
\r
300 gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),
\r
301 c.z + fs.getThickness() / 2.0);
\r
304 if (!(fs instanceof EllipticalFinSet))
\r
305 gl.glShadeModel(GLLightingFunc.GL_SMOOTH);
\r
309 gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);
\r
312 gl.glMatrixMode(GL.GL_TEXTURE);
\r
314 gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
\r
318 public void renderMotor(final GL2 gl, final Coordinate c, double l, double r) {
\r
319 final float outside[] = { 0.2f, 0.2f, 0.2f, 1.0f };
\r
320 gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, outside, 0);
\r
321 gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, outside, 0);
\r
325 gl.glTranslated(c.x, c.y, c.z);
\r
327 gl.glRotated(90, 0, 1.0, 0);
\r
329 glu.gluCylinder(q, r, r, l, LOD, 1);
\r
331 glu.gluDisk(q, r, 0, LOD, 2);
\r
333 gl.glTranslated(0, 0, l);
\r
334 gl.glRotated(180, 0, 1.0, 0);
\r
336 glu.gluDisk(q, r, 0, LOD, 2);
\r