create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / gui / figure3d / ComponentRenderer.java
1 package net.sf.openrocket.gui.figure3d;\r
2 \r
3 import java.util.HashMap;\r
4 import java.util.Map;\r
5 \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
16 \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
28 \r
29 /*\r
30  * @author Bill Kuker <bkuker@billkuker.com>\r
31  */\r
32 public class ComponentRenderer {\r
33         private static final LogHelper log = Application.getLogger();\r
34         \r
35         private int LOD = 80;\r
36 \r
37         GLU glu;\r
38         GLUquadric q;\r
39         GLUtessellator tobj;\r
40 \r
41         public ComponentRenderer() {\r
42 \r
43         }\r
44 \r
45         public void init(GLAutoDrawable drawable) {\r
46                 glu = new GLU();\r
47                 q = glu.gluNewQuadric();\r
48                 tobj = GLU.gluNewTess();\r
49                 glu.gluQuadricTexture(q, true);\r
50         }\r
51 \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
56         }\r
57         \r
58         public void renderGeometry(GL2 gl, RocketComponent c) {\r
59                 if (glu == null)\r
60                         throw new IllegalStateException(this + " Not Initialized");\r
61 \r
62                 glu.gluQuadricNormals(q, GLU.GLU_SMOOTH);\r
63                 \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
68                         }\r
69                         lists.clear();\r
70                         clearDisplayLists = false;\r
71                 }\r
72                 if ( lists.containsKey(c) ){\r
73                         gl.glCallList(lists.get(c));\r
74                 } else {\r
75                         int list = gl.glGenLists(1);\r
76                         gl.glNewList(list, GL2.GL_COMPILE_AND_EXECUTE);\r
77 \r
78                         Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0));\r
79 \r
80                         for (Coordinate o : oo) {\r
81                                 gl.glPushMatrix();\r
82 \r
83                                 gl.glTranslated(o.x, o.y, o.z);\r
84 \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
97                                 } else {\r
98                                         renderOther(gl, c);\r
99                                 }\r
100                                 gl.glPopMatrix();\r
101                         }\r
102                         \r
103                         gl.glEndList();\r
104                         lists.put(c, list);\r
105                 }\r
106         }\r
107 \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
114                         }\r
115                 }\r
116                 gl.glEnd();\r
117         }\r
118 \r
119         private void renderTransition(GL2 gl, Transition t) {\r
120                 gl.glRotated(90, 0, 1.0, 0);\r
121 \r
122                 if (t.getType() == Transition.Shape.CONICAL) {\r
123                         glu.gluCylinder(q, t.getForeRadius(), t.getAftRadius(),\r
124                                         t.getLength(), LOD, 1);\r
125                 } else {\r
126                         TransitionRenderer.drawTransition(gl, t, LOD, LOD);\r
127                 }\r
128 \r
129                 // Render AFT shoulder\r
130                 gl.glPushMatrix();\r
131                 gl.glTranslated(0, 0, t.getLength());\r
132 \r
133                 glu.gluCylinder(q, t.getAftShoulderRadius(), t.getAftShoulderRadius(),\r
134                                 t.getAftShoulderLength(), LOD, 1);\r
135 \r
136                 gl.glRotated(180, 0, 1.0, 0);\r
137 \r
138                 glu.gluDisk(q, t.getAftRadius(), t.getAftShoulderRadius(), LOD, 2);\r
139 \r
140                 gl.glTranslated(0, 0, -t.getAftShoulderLength());\r
141 \r
142                 if (t.isFilled() || t.isAftShoulderCapped()) {\r
143                         glu.gluDisk(q, t.getAftShoulderRadius(), 0, LOD, 2);\r
144                 }\r
145                 gl.glPopMatrix();\r
146 \r
147                 // Render Fore Shoulder\r
148                 gl.glPushMatrix();\r
149                 gl.glRotated(180, 0, 1.0, 0);\r
150 \r
151                 glu.gluCylinder(q, t.getForeShoulderRadius(),\r
152                                 t.getForeShoulderRadius(), t.getForeShoulderLength(), LOD, 1);\r
153 \r
154                 gl.glRotated(180, 0, 1.0, 0);\r
155 \r
156                 glu.gluDisk(q, t.getForeRadius(), t.getForeShoulderRadius(), LOD, 2);\r
157 \r
158                 gl.glTranslated(0, 0, -t.getForeShoulderLength());\r
159 \r
160                 if (t.isFilled() || t.isForeShoulderCapped()) {\r
161                         glu.gluDisk(q, t.getForeShoulderRadius(), 0, LOD, 2);\r
162                 }\r
163                 gl.glPopMatrix();\r
164 \r
165         }\r
166 \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
171         }\r
172 \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
177 \r
178                 gl.glRotated(180, 0, 1.0, 0);\r
179                 glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);\r
180 \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
184 \r
185                 gl.glTranslated(0, 0, -r.getLength());\r
186                 glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(),\r
187                                 r.getLength(), LOD, 1);\r
188 \r
189         }\r
190 \r
191         private void renderLug(GL2 gl, LaunchLug t) {\r
192 \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
196         }\r
197 \r
198         private void renderMassObject(GL2 gl, MassObject o) {\r
199                 gl.glRotated(90, 0, 1.0, 0);\r
200 \r
201                 MassObjectRenderer.drawMassObject(gl, o, LOD, LOD);\r
202         }\r
203 \r
204         private void renderFinSet(final GL2 gl, FinSet fs) {\r
205                 \r
206                 Coordinate finPoints[] = fs.getFinPointsWithTab();\r
207                 \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
212         \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
219                 }\r
220                 \r
221                 gl.glMatrixMode(GL.GL_TEXTURE);\r
222                 gl.glPushMatrix();\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
226                 \r
227                 gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);\r
228                 \r
229                 for (int fin = 0; fin < fs.getFinCount(); fin++) {\r
230 \r
231                         gl.glPushMatrix();\r
232 \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
236 \r
237                         GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {\r
238                                 @Override\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
243                                 }\r
244 \r
245                                 @Override\r
246                                 public void begin(int type) {\r
247                                         gl.glBegin(type);\r
248                                 }\r
249 \r
250                                 @Override\r
251                                 public void end() {\r
252                                         gl.glEnd();\r
253                                 }\r
254                         };\r
255 \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
259 \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
268 \r
269                         }\r
270                         GLU.gluTessEndContour(tobj);\r
271                         GLU.gluTessEndPolygon(tobj);\r
272 \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
281 \r
282                         }\r
283                         GLU.gluTessEndContour(tobj);\r
284                         GLU.gluTessEndPolygon(tobj);\r
285 \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
292                                 // if ( i > 1 ){\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
296                                 // }\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
302                         }\r
303                         gl.glEnd();\r
304                         if (!(fs instanceof EllipticalFinSet))\r
305                                 gl.glShadeModel(GLLightingFunc.GL_SMOOTH);\r
306 \r
307                         gl.glPopMatrix();\r
308 \r
309                         gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);\r
310                 }\r
311                 \r
312                 gl.glMatrixMode(GL.GL_TEXTURE);\r
313                 gl.glPopMatrix();\r
314                 gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
315                 \r
316         }\r
317 \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
322 \r
323                 gl.glPushMatrix();\r
324 \r
325                 gl.glTranslated(c.x, c.y, c.z);\r
326 \r
327                 gl.glRotated(90, 0, 1.0, 0);\r
328 \r
329                 glu.gluCylinder(q, r, r, l, LOD, 1);\r
330 \r
331                 glu.gluDisk(q, r, 0, LOD, 2);\r
332 \r
333                 gl.glTranslated(0, 0, l);\r
334                 gl.glRotated(180, 0, 1.0, 0);\r
335 \r
336                 glu.gluDisk(q, r, 0, LOD, 2);\r
337 \r
338                 gl.glPopMatrix();\r
339         }\r
340 }\r