<classpathentry kind="lib" path="lib-test/uispec4j-2.3-jdk16.jar"/>
<classpathentry kind="lib" path="resources"/>
<classpathentry kind="lib" path="lib/jspf.core-1.0.2.jar" sourcepath="/home/sampo/Projects/lib/jspf/documentation/api"/>
- <classpathentry kind="lib" path="lib/opencsv-2.3.jar"/>
- <classpathentry kind="lib" path="lib/exp4j-0.2.9.jar"/>
+ <classpathentry kind="lib" path="lib/opencsv-2.3.jar"/>\r
+ <classpathentry kind="lib" path="lib/native/gluegen-rt.jar"/>
+ <classpathentry kind="lib" path="lib/native/jogl.all.jar"/>\r
+ <classpathentry kind="lib" path="lib/exp4j-0.2.9.jar"/>\r
<classpathentry kind="output" path="bin"/>
</classpath>
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
</target>
-
- <!-- JAR -->
- <target name="jar" depends="build" description="Create the OpenRocket jar file">
- <copy todir="${dist.dir}/">
- <fileset dir="." includes="LICENSE.TXT README.TXT ChangeLog ReleaseNotes fileformat.txt" />
- <fileset dir="resources/"/>
+ <!-- Executible Eclipse-Jar-In-Jar style JAR -->
+ <target name="jar" depends="core-jar" description="Create the OpenRocket jar-in-jar Executable">
+ <mkdir dir="${jar.dir}" />
+ <jar destfile="${jar.file}">
+ <manifest>
+ <attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
+ <attribute name="Rsrc-Main-Class" value="${main-class}" />
+ <attribute name="SplashScreen-Image" value="pix/splashscreen.png" />
+ <attribute name="Class-Path" value="." />
+ <attribute name="Rsrc-Class-Path" value="./ main/${ant.project.name}-Core.jar lib/jfreechart-1.0.13.jar lib/jcommon-1.0.16.jar lib/gluegen-rt.jar lib/miglayout15-swing.jar lib/iText-5.0.2.jar lib/jogl.all.jar lib/opencsv-2.3.jar" />
+ </manifest>
+
+ <!-- Unzip the Eclipse JIJ Loader -->
+ <zipfileset src="lib/jar-in-jar-loader.jar" />
+
+ <!-- Include, in the root of the JAR, the resources needed by OR -->
<fileset dir="src/" includes="META-INF/" />
- </copy>
- <mkdir dir="${jar.dir}"/>
- <jar destfile="${jar.file}" basedir="${dist.dir}">
+ <fileset dir="resources/" />
+
+ <!-- Include the core OpenRocket JAR -->
+ <zipfileset dir="${build.dir}/" prefix="main">
+ <include name="${ant.project.name}-Core.jar"/>
+ </zipfileset>
+
+ <!-- Include libraries needed by OR -->
+ <zipfileset dir="${lib.dir}" prefix="lib">
+ <include name="*.jar"/>
+ </zipfileset>
+ <zipfileset dir="${lib.dir}/native" prefix="lib">
+ <include name="*.jar"/>
+ </zipfileset>
+
+ <!-- Include metafiles about OR -->
+ <fileset dir="." includes="LICENSE.TXT README.TXT ChangeLog ReleaseNotes fileformat.txt" />
+ </jar>
+ </target>
+
+
+ <!-- Core OpenRocket JAR -->
+ <target name="core-jar" depends="build" description="Create the OpenRocket code-only jar file">
+ <jar destfile="${build.dir}/${ant.project.name}-Core.jar" basedir="${dist.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="SplashScreen-Image" value="pix/splashscreen.png"/>
</manifest>
- <zipfileset src="lib/miglayout15-swing.jar" />
- <zipfileset src="lib/jcommon-1.0.16.jar" />
- <zipfileset src="lib/jfreechart-1.0.13.jar" />
- <zipfileset src="lib/iText-5.0.2.jar" />
- <zipfileset src="lib/opencsv-2.3.jar" />
<zipfileset src="lib/exp4j-0.2.9.jar" />
</jar>
</target>
--- /dev/null
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+import javax.media.opengl.fixedfunc.GLMatrixFunc;\r
+import javax.media.opengl.glu.GLU;\r
+import javax.media.opengl.glu.GLUquadric;\r
+import javax.media.opengl.glu.GLUtessellator;\r
+import javax.media.opengl.glu.GLUtessellatorCallback;\r
+import javax.media.opengl.glu.GLUtessellatorCallbackAdapter;\r
+\r
+import net.sf.openrocket.logging.LogHelper;\r
+import net.sf.openrocket.rocketcomponent.BodyTube;\r
+import net.sf.openrocket.rocketcomponent.EllipticalFinSet;\r
+import net.sf.openrocket.rocketcomponent.FinSet;\r
+import net.sf.openrocket.rocketcomponent.LaunchLug;\r
+import net.sf.openrocket.rocketcomponent.MassObject;\r
+import net.sf.openrocket.rocketcomponent.RingComponent;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Coordinate;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class ComponentRenderer {\r
+ private static final LogHelper log = Application.getLogger();\r
+ \r
+ private int LOD = 80;\r
+\r
+ GLU glu;\r
+ GLUquadric q;\r
+ GLUtessellator tobj;\r
+\r
+ public ComponentRenderer() {\r
+\r
+ }\r
+\r
+ public void init(GLAutoDrawable drawable) {\r
+ glu = new GLU();\r
+ q = glu.gluNewQuadric();\r
+ tobj = GLU.gluNewTess();\r
+ glu.gluQuadricTexture(q, true);\r
+ }\r
+\r
+ private Map<RocketComponent, Integer> lists = new HashMap<RocketComponent, Integer>();\r
+ private boolean clearDisplayLists = false;\r
+ public void updateFigure() {\r
+ clearDisplayLists = true;\r
+ }\r
+ \r
+ public void renderGeometry(GL2 gl, RocketComponent c) {\r
+ if (glu == null)\r
+ throw new IllegalStateException(this + " Not Initialized");\r
+\r
+ glu.gluQuadricNormals(q, GLU.GLU_SMOOTH);\r
+ \r
+ if ( clearDisplayLists ){\r
+ log.debug("Clearing Display Lists");\r
+ for ( int i : lists.values() ){\r
+ gl.glDeleteLists(i,1);\r
+ }\r
+ lists.clear();\r
+ clearDisplayLists = false;\r
+ }\r
+ if ( lists.containsKey(c) ){\r
+ gl.glCallList(lists.get(c));\r
+ } else {\r
+ int list = gl.glGenLists(1);\r
+ gl.glNewList(list, GL2.GL_COMPILE_AND_EXECUTE);\r
+\r
+ Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0));\r
+\r
+ for (Coordinate o : oo) {\r
+ gl.glPushMatrix();\r
+\r
+ gl.glTranslated(o.x, o.y, o.z);\r
+\r
+ if (c instanceof BodyTube) {\r
+ renderTube(gl, (BodyTube) c);\r
+ } else if (c instanceof LaunchLug) {\r
+ renderLug(gl, (LaunchLug) c);\r
+ } else if (c instanceof RingComponent) {\r
+ renderRing(gl, (RingComponent) c);\r
+ } else if (c instanceof Transition) {\r
+ renderTransition(gl, (Transition) c);\r
+ } else if (c instanceof MassObject) {\r
+ renderMassObject(gl, (MassObject) c);\r
+ } else if (c instanceof FinSet) {\r
+ renderFinSet(gl, (FinSet) c);\r
+ } else {\r
+ renderOther(gl, c);\r
+ }\r
+ gl.glPopMatrix();\r
+ }\r
+ \r
+ gl.glEndList();\r
+ lists.put(c, list);\r
+ }\r
+ }\r
+\r
+ private void renderOther(GL2 gl, RocketComponent c) {\r
+ gl.glBegin(GL.GL_LINES);\r
+ for (Coordinate cc : c.getComponentBounds()) {\r
+ for (Coordinate ccc : c.getComponentBounds()) {\r
+ gl.glVertex3d(cc.x, cc.y, cc.z);\r
+ gl.glVertex3d(ccc.x, ccc.y, ccc.z);\r
+ }\r
+ }\r
+ gl.glEnd();\r
+ }\r
+\r
+ private void renderTransition(GL2 gl, Transition t) {\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+\r
+ if (t.getType() == Transition.Shape.CONICAL) {\r
+ glu.gluCylinder(q, t.getForeRadius(), t.getAftRadius(),\r
+ t.getLength(), LOD, 1);\r
+ } else {\r
+ TransitionRenderer.drawTransition(gl, t, LOD, LOD);\r
+ }\r
+\r
+ // Render AFT shoulder\r
+ gl.glPushMatrix();\r
+ gl.glTranslated(0, 0, t.getLength());\r
+\r
+ glu.gluCylinder(q, t.getAftShoulderRadius(), t.getAftShoulderRadius(),\r
+ t.getAftShoulderLength(), LOD, 1);\r
+\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+\r
+ glu.gluDisk(q, t.getAftRadius(), t.getAftShoulderRadius(), LOD, 2);\r
+\r
+ gl.glTranslated(0, 0, -t.getAftShoulderLength());\r
+\r
+ if (t.isFilled() || t.isAftShoulderCapped()) {\r
+ glu.gluDisk(q, t.getAftShoulderRadius(), 0, LOD, 2);\r
+ }\r
+ gl.glPopMatrix();\r
+\r
+ // Render Fore Shoulder\r
+ gl.glPushMatrix();\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+\r
+ glu.gluCylinder(q, t.getForeShoulderRadius(),\r
+ t.getForeShoulderRadius(), t.getForeShoulderLength(), LOD, 1);\r
+\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+\r
+ glu.gluDisk(q, t.getForeRadius(), t.getForeShoulderRadius(), LOD, 2);\r
+\r
+ gl.glTranslated(0, 0, -t.getForeShoulderLength());\r
+\r
+ if (t.isFilled() || t.isForeShoulderCapped()) {\r
+ glu.gluDisk(q, t.getForeShoulderRadius(), 0, LOD, 2);\r
+ }\r
+ gl.glPopMatrix();\r
+\r
+ }\r
+\r
+ private void renderTube(GL2 gl, BodyTube t) {\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+ glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),\r
+ t.getLength(), LOD, 1);\r
+ }\r
+\r
+ private void renderRing(GL2 gl, RingComponent r) {\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+ glu.gluCylinder(q, r.getOuterRadius(), r.getOuterRadius(),\r
+ r.getLength(), LOD, 1);\r
+\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+ glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);\r
+\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+ gl.glTranslated(0, 0, r.getLength());\r
+ glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);\r
+\r
+ gl.glTranslated(0, 0, -r.getLength());\r
+ glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(),\r
+ r.getLength(), LOD, 1);\r
+\r
+ }\r
+\r
+ private void renderLug(GL2 gl, LaunchLug t) {\r
+\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+ glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),\r
+ t.getLength(), LOD, 1);\r
+ }\r
+\r
+ private void renderMassObject(GL2 gl, MassObject o) {\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+\r
+ MassObjectRenderer.drawMassObject(gl, o, LOD, LOD);\r
+ }\r
+\r
+ private void renderFinSet(final GL2 gl, FinSet fs) {\r
+ \r
+ Coordinate finPoints[] = fs.getFinPointsWithTab();\r
+ \r
+ double minX = Double.MAX_VALUE;\r
+ double minY = Double.MAX_VALUE;\r
+ double maxX = Double.MIN_VALUE;\r
+ double maxY = Double.MIN_VALUE;\r
+ \r
+ for (int i = 0; i < finPoints.length; i++) {\r
+ Coordinate c = finPoints[i];\r
+ minX = Math.min(c.x, minX); \r
+ minY = Math.min(c.y, minY);\r
+ maxX = Math.max(c.x, maxX);\r
+ maxY = Math.max(c.y, maxY); \r
+ }\r
+ \r
+ gl.glMatrixMode(GL.GL_TEXTURE);\r
+ gl.glPushMatrix();\r
+ gl.glScaled(1/(maxX-minX), 1/(maxY-minY), 0);\r
+ gl.glTranslated(-minX, -minY - fs.getBodyRadius(), 0);\r
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+ \r
+ gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);\r
+ \r
+ for (int fin = 0; fin < fs.getFinCount(); fin++) {\r
+\r
+ gl.glPushMatrix();\r
+\r
+ gl.glTranslated(fs.getLength() / 2, 0, 0);\r
+ gl.glRotated(fs.getCantAngle() * (180.0 / Math.PI), 0, 1, 0);\r
+ gl.glTranslated(-fs.getLength() / 2, 0, 0);\r
+\r
+ GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {\r
+ @Override\r
+ public void vertex(Object vertexData) {\r
+ double d[] = (double[]) vertexData;\r
+ gl.glTexCoord2d(d[0], d[1]);\r
+ gl.glVertex3dv(d, 0);\r
+ }\r
+\r
+ @Override\r
+ public void begin(int type) {\r
+ gl.glBegin(type);\r
+ }\r
+\r
+ @Override\r
+ public void end() {\r
+ gl.glEnd();\r
+ }\r
+ };\r
+\r
+ GLU.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, cb);\r
+ GLU.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, cb);\r
+ GLU.gluTessCallback(tobj, GLU.GLU_TESS_END, cb);\r
+\r
+ GLU.gluTessBeginPolygon(tobj, null);\r
+ GLU.gluTessBeginContour(tobj);\r
+ gl.glNormal3f(0, 0, 1);\r
+ for (int i = finPoints.length - 1; i >= 0; i--) {\r
+ Coordinate c = finPoints[i];\r
+ double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),\r
+ c.z + fs.getThickness() / 2.0 };\r
+ GLU.gluTessVertex(tobj, p, 0, p);\r
+\r
+ }\r
+ GLU.gluTessEndContour(tobj);\r
+ GLU.gluTessEndPolygon(tobj);\r
+\r
+ GLU.gluTessBeginPolygon(tobj, null);\r
+ GLU.gluTessBeginContour(tobj);\r
+ gl.glNormal3f(0, 0, -1);\r
+ for (int i = 0; i < finPoints.length; i++) {\r
+ Coordinate c = finPoints[i];\r
+ double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),\r
+ c.z - fs.getThickness() / 2.0 };\r
+ GLU.gluTessVertex(tobj, p, 0, p);\r
+\r
+ }\r
+ GLU.gluTessEndContour(tobj);\r
+ GLU.gluTessEndPolygon(tobj);\r
+\r
+ // Strip around the edge\r
+ if (!(fs instanceof EllipticalFinSet))\r
+ gl.glShadeModel(GLLightingFunc.GL_FLAT);\r
+ gl.glBegin(GL.GL_TRIANGLE_STRIP);\r
+ for (int i = 0; i <= finPoints.length; i++) {\r
+ Coordinate c = finPoints[i % finPoints.length];\r
+ // if ( i > 1 ){\r
+ Coordinate c2 = finPoints[(i - 1 + finPoints.length)\r
+ % finPoints.length];\r
+ gl.glNormal3d(c2.y - c.y, c.x - c2.x, 0);\r
+ // }\r
+ gl.glTexCoord2d(c.x, c.y + fs.getBodyRadius());\r
+ gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),\r
+ c.z - fs.getThickness() / 2.0);\r
+ gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),\r
+ c.z + fs.getThickness() / 2.0);\r
+ }\r
+ gl.glEnd();\r
+ if (!(fs instanceof EllipticalFinSet))\r
+ gl.glShadeModel(GLLightingFunc.GL_SMOOTH);\r
+\r
+ gl.glPopMatrix();\r
+\r
+ gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);\r
+ }\r
+ \r
+ gl.glMatrixMode(GL.GL_TEXTURE);\r
+ gl.glPopMatrix();\r
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+ \r
+ }\r
+\r
+ public void renderMotor(final GL2 gl, final Coordinate c, double l, double r) {\r
+ final float outside[] = { 0.2f, 0.2f, 0.2f, 1.0f };\r
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, outside, 0);\r
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, outside, 0);\r
+\r
+ gl.glPushMatrix();\r
+\r
+ gl.glTranslated(c.x, c.y, c.z);\r
+\r
+ gl.glRotated(90, 0, 1.0, 0);\r
+\r
+ glu.gluCylinder(q, r, r, l, LOD, 1);\r
+\r
+ glu.gluDisk(q, r, 0, LOD, 2);\r
+\r
+ gl.glTranslated(0, 0, l);\r
+ gl.glRotated(180, 0, 1.0, 0);\r
+\r
+ glu.gluDisk(q, r, 0, LOD, 2);\r
+\r
+ gl.glPopMatrix();\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ ** License Applicability. Except to the extent portions of this file are\r
+ ** made subject to an alternative license as permitted in the SGI Free\r
+ ** Software License B, Version 2.0 (the "License"), the contents of this\r
+ ** file are subject only to the provisions of the License. You may not use\r
+ ** this file except in compliance with the License. You may obtain a copy\r
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\r
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\r
+ ** \r
+ ** http://oss.sgi.com/projects/FreeB\r
+ ** \r
+ ** Note that, as provided in the License, the Software is distributed on an\r
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\r
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\r
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\r
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\r
+ ** \r
+ ** NOTE: The Original Code (as defined below) has been licensed to Sun\r
+ ** Microsystems, Inc. ("Sun") under the SGI Free Software License B\r
+ ** (Version 1.1), shown above ("SGI License"). Pursuant to Section\r
+ ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to\r
+ ** you under an alternative license ("Alternative License"). This\r
+ ** Alternative License includes all of the provisions of the SGI License\r
+ ** except that Section 2.2 and 11 are omitted. Any differences between\r
+ ** the Alternative License and the SGI License are offered solely by Sun\r
+ ** and not by SGI.\r
+ **\r
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,\r
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\r
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.\r
+ ** Copyright in any portions created by third parties is as indicated\r
+ ** elsewhere herein. All Rights Reserved.\r
+ ** \r
+ ** Additional Notice Provisions: The application programming interfaces\r
+ ** established by SGI in conjunction with the Original Code are The\r
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released\r
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version\r
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X\r
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software\r
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation\r
+ ** published by SGI, but has not been independently verified as being\r
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.\r
+ **\r
+ ** $Date: 2009-03-04 17:23:34 -0800 (Wed, 04 Mar 2009) $ $Revision: 1856 $\r
+ ** $Header$\r
+ */\r
+\r
+/* \r
+ * Copyright (c) 2002-2004 LWJGL Project\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are \r
+ * met:\r
+ * \r
+ * * Redistributions of source code must retain the above copyright \r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of 'LWJGL' nor the names of \r
+ * its contributors may be used to endorse or promote products derived \r
+ * from this software without specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, \r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR \r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING \r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are\r
+ * met:\r
+ * \r
+ * - Redistribution of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * - Redistribution in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * \r
+ * Neither the name of Sun Microsystems, Inc. or the names of\r
+ * contributors may be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ * \r
+ * This software is provided "AS IS," without a warranty of any kind. ALL\r
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,\r
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A\r
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN\r
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR\r
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR\r
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR\r
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR\r
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE\r
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,\r
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF\r
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r
+ * \r
+ * You acknowledge that this software is not designed or intended for use\r
+ * in the design, construction, operation or maintenance of any nuclear\r
+ * facility.\r
+ */\r
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+\r
+import net.sf.openrocket.rocketcomponent.MassObject;\r
+\r
+public final class MassObjectRenderer {\r
+ private static final boolean textureFlag = true;\r
+\r
+ private MassObjectRenderer() {\r
+ }\r
+\r
+ public static final void drawMassObject(final GL2 gl, final MassObject o,\r
+ final int slices, final int stacks) {\r
+\r
+ double da, r, dz;\r
+ double x, y, z, nz, nsign;\r
+ int i, j;\r
+\r
+ nsign = 1.0f;\r
+\r
+ da = 2.0f * PI / slices;\r
+ dz = o.getLength() / stacks;\r
+\r
+ double ds = 1.0f / slices;\r
+ double dt = 1.0f / stacks;\r
+ double t = 0.0f;\r
+ z = 0.0f;\r
+ for (j = 0; j < stacks; j++) {\r
+ r = getRadius(o, z);\r
+ double rNext = getRadius(o, z + dz);\r
+ if (j == stacks - 1)\r
+ rNext = 0;\r
+\r
+ if (j == stacks - 1)\r
+ rNext = 0;\r
+\r
+ // Z component of normal vectors\r
+ nz = -(rNext - r) / dz;\r
+\r
+ double s = 0.0f;\r
+ glBegin(gl, GL2.GL_QUAD_STRIP);\r
+ for (i = 0; i <= slices; i++) {\r
+ if (i == slices) {\r
+ x = sin(0.0f);\r
+ y = cos(0.0f);\r
+ } else {\r
+ x = sin((i * da));\r
+ y = cos((i * da));\r
+ }\r
+ if (nsign == 1.0f) {\r
+ normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+ TXTR_COORD(gl, s, t);\r
+ glVertex3d(gl, (x * r), (y * r), z);\r
+ normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+ TXTR_COORD(gl, s, t + dt);\r
+ glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+ } else {\r
+ normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+ TXTR_COORD(gl, s, t);\r
+ glVertex3d(gl, (x * r), (y * r), z);\r
+ normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+ TXTR_COORD(gl, s, t + dt);\r
+ glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+ }\r
+ s += ds;\r
+ } // for slices\r
+ glEnd(gl);\r
+ // r += dr;\r
+ t += dt;\r
+ z += dz;\r
+ } // for stacks\r
+ }\r
+\r
+ private static final double getRadius(MassObject o, double z) {\r
+ double arc = Math.min(o.getLength(), 2 * o.getRadius()) * 0.35f;\r
+ double r = o.getRadius();\r
+ if (z == 0 || z == o.getLength())\r
+ return 0;\r
+ if (z < arc) {\r
+ double zz = z - arc;\r
+ return (r - arc) + Math.sqrt(arc * arc - zz * zz);\r
+ }\r
+ if (z > o.getLength() - arc) {\r
+ double zz = (z - o.getLength() + arc);\r
+ return (r - arc) + Math.sqrt(arc * arc - zz * zz);\r
+ }\r
+ return o.getRadius();\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // Internals only below this point\r
+ //\r
+\r
+ private static final double PI = Math.PI;\r
+\r
+ private static final void glBegin(GL gl, int mode) {\r
+ gl.getGL2().glBegin(mode);\r
+ }\r
+\r
+ private static final void glEnd(GL gl) {\r
+ gl.getGL2().glEnd();\r
+ }\r
+\r
+ private static final void glVertex3d(GL gl, double x, double y, double z) {\r
+ gl.getGL2().glVertex3d(x, y, z);\r
+ }\r
+\r
+ private static final void glNormal3d(GL gl, double x, double y, double z) {\r
+ gl.getGL2().glNormal3d(x, y, z);\r
+ }\r
+\r
+ private static final void glTexCoord2d(GL gl, double x, double y) {\r
+ gl.getGL2().glTexCoord2d(x, y);\r
+ }\r
+\r
+ /**\r
+ * Call glNormal3f after scaling normal to unit length.\r
+ * \r
+ * @param x\r
+ * @param y\r
+ * @param z\r
+ */\r
+ private static final void normal3d(GL gl, double x, double y, double z) {\r
+ double mag;\r
+\r
+ mag = Math.sqrt(x * x + y * y + z * z);\r
+ if (mag > 0.00001F) {\r
+ x /= mag;\r
+ y /= mag;\r
+ z /= mag;\r
+ }\r
+ glNormal3d(gl, x, y, z);\r
+ }\r
+\r
+ private static final void TXTR_COORD(GL gl, double x, double y) {\r
+ if (textureFlag)\r
+ glTexCoord2d(gl, x, y);\r
+ }\r
+\r
+ private static final double sin(double r) {\r
+ return Math.sin(r);\r
+ }\r
+\r
+ private static final double cos(double r) {\r
+ return Math.cos(r);\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.gui.figure3d;\r
+import java.awt.BorderLayout;\r
+\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+\r
+import net.sf.openrocket.database.ComponentPresetDatabase;\r
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.file.DatabaseMotorFinder;\r
+import net.sf.openrocket.file.openrocket.importt.OpenRocketLoader;\r
+import net.sf.openrocket.gui.main.componenttree.ComponentTree;\r
+import net.sf.openrocket.gui.scalefigure.RocketPanel;\r
+import net.sf.openrocket.gui.util.SwingPreferences;\r
+import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
+import net.sf.openrocket.startup.Application;\r
+\r
+/**\r
+ * An application for quickly testing 3d figure witout all the OpenRocket user interface\r
+ * \r
+ * @author bkuker\r
+ *\r
+ */\r
+public class Quick3dMain {\r
+\r
+ /**\r
+ * @param args\r
+ */\r
+ public static void main(String[] args) throws Exception {\r
+ Application.setBaseTranslator(new ResourceBundleTranslator(\r
+ "l10n.messages"));\r
+ Application.setMotorSetDatabase(new ThrustCurveMotorSetDatabase(false) {\r
+ {\r
+ startLoading();\r
+ }\r
+\r
+ @Override\r
+ protected void loadMotors() {\r
+ }\r
+ });\r
+ Application.setPreferences(new SwingPreferences());\r
+ \r
+ // Must be done after localization is initialized\r
+ ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();\r
+ componentPresetDao.load("datafiles", ".*csv");\r
+ Application.setComponentPresetDao( componentPresetDao );\r
+\r
+ OpenRocketDocument doc = new OpenRocketLoader().loadFromStream(\r
+ Quick3dMain.class.getResourceAsStream("/datafiles/examples/Clustered rocket design.ork"),\r
+ new DatabaseMotorFinder());\r
+\r
+ JFrame ff = new JFrame();\r
+ ff.setSize(1200, 400);\r
+ ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
+\r
+ RocketPanel panel;\r
+\r
+ panel = new RocketPanel(doc);\r
+\r
+ ComponentTree ct = new ComponentTree(doc);\r
+ panel.setSelectionModel(ct.getSelectionModel());\r
+\r
+ JPanel p = new JPanel();\r
+ p.setLayout(new BorderLayout());\r
+ p.add(ct, BorderLayout.WEST);\r
+ p.add(panel, BorderLayout.CENTER);\r
+ ff.setContentPane(p);\r
+ ff.setVisible(true);\r
+ }\r
+}\r
--- /dev/null
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.Point;\r
+import java.awt.Rectangle;\r
+import java.awt.RenderingHints;\r
+import java.awt.event.HierarchyEvent;\r
+import java.awt.event.HierarchyListener;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.image.BufferedImage;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.GLCapabilities;\r
+import javax.media.opengl.GLEventListener;\r
+import javax.media.opengl.GLProfile;\r
+import javax.media.opengl.awt.GLCanvas;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+import javax.media.opengl.fixedfunc.GLMatrixFunc;\r
+import javax.media.opengl.glu.GLU;\r
+import javax.swing.JLabel;\r
+import javax.swing.JPanel;\r
+import javax.swing.JPopupMenu;\r
+import javax.swing.SwingUtilities;\r
+import javax.swing.event.MouseInputAdapter;\r
+\r
+import net.sf.openrocket.gui.figureelements.CGCaret;\r
+import net.sf.openrocket.gui.figureelements.CPCaret;\r
+import net.sf.openrocket.gui.figureelements.FigureElement;\r
+import net.sf.openrocket.logging.LogHelper;\r
+import net.sf.openrocket.rocketcomponent.Configuration;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Coordinate;\r
+import net.sf.openrocket.util.MathUtil;\r
+\r
+import com.jogamp.opengl.util.awt.Overlay;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class RocketFigure3d extends JPanel implements GLEventListener {\r
+ private static final long serialVersionUID = 1L;\r
+ private static final LogHelper log = Application.getLogger();\r
+ \r
+ static {\r
+ //this allows the GL canvas and things like the motor selection\r
+ //drop down to z-order themselves.\r
+ JPopupMenu.setDefaultLightWeightPopupEnabled(false);\r
+ }\r
+\r
+ private static final double fovY = 15.0;\r
+ private static double fovX = Double.NaN;\r
+ private static final int CARET_SIZE = 20;\r
+ \r
+ private Configuration configuration;\r
+ private GLCanvas canvas;\r
+\r
+\r
+ \r
+ private Overlay extrasOverlay, caretOverlay;\r
+ private BufferedImage cgCaretRaster, cpCaretRaster;\r
+ private volatile boolean redrawExtras = true;\r
+\r
+ private final ArrayList<FigureElement> relativeExtra = new ArrayList<FigureElement>();\r
+ private final ArrayList<FigureElement> absoluteExtra = new ArrayList<FigureElement>();\r
+\r
+ private double roll = 0;\r
+ private double yaw = 0;\r
+\r
+ Point pickPoint = null;\r
+ MouseEvent pickEvent;\r
+\r
+ float[] lightPosition = new float[] { 1, 4, 1, 0 };\r
+\r
+ RocketRenderer rr = new RocketRenderer();\r
+\r
+ public RocketFigure3d(Configuration config) {\r
+ this.configuration = config;\r
+ this.setLayout(new BorderLayout());\r
+\r
+ addHierarchyListener(new HierarchyListener() {\r
+ @Override\r
+ public void hierarchyChanged(HierarchyEvent e) {\r
+ initGLCanvas();\r
+ RocketFigure3d.this.removeHierarchyListener(this);\r
+ }\r
+ });\r
+ }\r
+ \r
+ private void initGLCanvas(){\r
+ log.debug("Initializing RocketFigure3D OpenGL Canvas");\r
+ try {\r
+ log.debug("Setting up GL capabilities...");\r
+ GLProfile glp = GLProfile.getDefault();\r
+ GLCapabilities caps = new GLCapabilities(glp);\r
+ caps.setSampleBuffers(true);\r
+ caps.setNumSamples(6);\r
+ caps.setStencilBits(1);\r
+\r
+ log.debug("Creating OpenGL Canvas");\r
+ canvas = new GLCanvas(caps);\r
+\r
+ canvas.addGLEventListener(this);\r
+ this.add(canvas, BorderLayout.CENTER);\r
+\r
+ setupMouseListeners();\r
+ rasterizeCarets();\r
+ \r
+ } catch (Throwable t) {\r
+ log.error("An error occurred creating 3d View", t);\r
+ canvas = null;\r
+ this.add(new JLabel("Unable to load 3d Libraries: "\r
+ + t.getMessage()));\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Set up the standard rendering hints on the Graphics2D\r
+ */\r
+ private static void setRenderingHints(Graphics2D g){\r
+ g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,\r
+ RenderingHints.VALUE_STROKE_NORMALIZE);\r
+ g.setRenderingHint(RenderingHints.KEY_RENDERING,\r
+ RenderingHints.VALUE_RENDER_QUALITY);\r
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
+ RenderingHints.VALUE_ANTIALIAS_ON);\r
+ }\r
+ \r
+ /**\r
+ * Rasterize the carets into 2 buffered images that I can blit onto the\r
+ * 3d display every redraw without all of the caret shape rendering overhead\r
+ */\r
+ private void rasterizeCarets(){\r
+ Graphics2D g2d;\r
+ \r
+ //Rasterize a CG Caret\r
+ cgCaretRaster = new BufferedImage(CARET_SIZE, CARET_SIZE, BufferedImage.TYPE_4BYTE_ABGR);\r
+ g2d = cgCaretRaster.createGraphics();\r
+ setRenderingHints(g2d);\r
+ \r
+ g2d.setBackground(new Color(0, 0, 0, 0));\r
+ g2d.clearRect(0, 0, CARET_SIZE, CARET_SIZE);\r
+ \r
+ new CGCaret(CARET_SIZE/2,CARET_SIZE/2).paint(g2d, 1.0);\r
+ \r
+ g2d.dispose();\r
+\r
+ //Rasterize a CP Caret\r
+ cpCaretRaster = new BufferedImage(CARET_SIZE, CARET_SIZE, BufferedImage.TYPE_4BYTE_ABGR);\r
+ g2d = cpCaretRaster.createGraphics();\r
+ setRenderingHints(g2d);\r
+ \r
+ g2d.setBackground(new Color(0, 0, 0, 0));\r
+ g2d.clearRect(0, 0, CARET_SIZE, CARET_SIZE);\r
+ \r
+ new CPCaret(CARET_SIZE/2,CARET_SIZE/2).paint(g2d, 1.0);\r
+ \r
+ g2d.dispose();\r
+ \r
+ }\r
+\r
+ private void setupMouseListeners() {\r
+ MouseInputAdapter a = new MouseInputAdapter() {\r
+ int lastX;\r
+ int lastY;\r
+ MouseEvent pressEvent;\r
+\r
+ @Override\r
+ public void mousePressed(MouseEvent e) {\r
+ lastX = e.getX();\r
+ lastY = e.getY();\r
+ pressEvent = e;\r
+ }\r
+\r
+ @Override\r
+ public void mouseClicked(MouseEvent e) {\r
+ pickPoint = new Point(lastX, canvas.getHeight() - lastY);\r
+ pickEvent = e;\r
+ internalRepaint();\r
+ }\r
+\r
+ @Override\r
+ public void mouseDragged(MouseEvent e) {\r
+ int dx = lastX - e.getX();\r
+ int dy = lastY - e.getY();\r
+ lastX = e.getX();\r
+ lastY = e.getY();\r
+\r
+ if (pressEvent.getButton() == MouseEvent.BUTTON1) {\r
+ if (Math.abs(dx) > Math.abs(dy)) {\r
+ setYaw(yaw - (float) dx / 100.0);\r
+ } else {\r
+ if ( yaw > Math.PI/2.0 && yaw < 3.0*Math.PI/2.0 ){\r
+ dy = -dy;\r
+ }\r
+ setRoll(roll - (float) dy / 100.0);\r
+ }\r
+ } else {\r
+ lightPosition[0] -= 0.1f * dx;\r
+ lightPosition[1] += 0.1f * dy;\r
+ internalRepaint();\r
+ }\r
+ }\r
+ };\r
+ canvas.addMouseMotionListener(a);\r
+ canvas.addMouseListener(a);\r
+ }\r
+\r
+ public void setConfiguration(Configuration configuration) {\r
+ this.configuration = configuration;\r
+ updateFigure();\r
+ }\r
+\r
+ @Override\r
+ public void display(GLAutoDrawable drawable) {\r
+ GL2 gl = drawable.getGL().getGL2();\r
+ GLU glu = new GLU();\r
+\r
+ gl.glEnable(GL.GL_MULTISAMPLE);\r
+\r
+ gl.glClearColor(1, 1, 1, 1);\r
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);\r
+\r
+ setupView(gl, glu);\r
+\r
+ if (pickPoint != null) {\r
+ gl.glDisable(GLLightingFunc.GL_LIGHTING);\r
+ final RocketComponent picked = rr.pick(drawable, configuration,\r
+ pickPoint, pickEvent.isShiftDown()?selection:null );\r
+ if (csl != null && picked != null) {\r
+ final MouseEvent e = pickEvent;\r
+ SwingUtilities.invokeLater(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ csl.componentClicked(new RocketComponent[] { picked },\r
+ e);\r
+ }\r
+ });\r
+\r
+ }\r
+ pickPoint = null;\r
+\r
+ gl.glClearColor(1, 1, 1, 1);\r
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);\r
+\r
+ gl.glEnable(GLLightingFunc.GL_LIGHTING);\r
+ }\r
+ rr.render(drawable, configuration, selection);\r
+ \r
+ drawExtras(gl, glu);\r
+ drawCarets(gl, glu);\r
+ }\r
+\r
+ \r
+ private void drawCarets(GL2 gl, GLU glu) {\r
+ final Graphics2D og2d = caretOverlay.createGraphics();\r
+ setRenderingHints(og2d);\r
+ \r
+ og2d.setBackground(new Color(0, 0, 0, 0));\r
+ og2d.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());\r
+ caretOverlay.markDirty(0, 0, canvas.getWidth(), canvas.getHeight());\r
+\r
+ // The existing relative Extras don't really work right for 3d.\r
+ Coordinate pCP = project(cp, gl, glu);\r
+ Coordinate pCG = project(cg, gl, glu);\r
+\r
+ final int d = CARET_SIZE/2;\r
+ \r
+ //z order the carets \r
+ if (pCG.z < pCP.z) {\r
+ //Subtract half of the caret size, so they are centered ( The +/- d in each translate)\r
+ //Flip the sense of the Y coordinate from GL to normal (Y+ up/down)\r
+ og2d.drawRenderedImage(\r
+ cpCaretRaster,\r
+ AffineTransform.getTranslateInstance((pCP.x - d),\r
+ canvas.getHeight() - (pCP.y + d)));\r
+ og2d.drawRenderedImage(\r
+ cgCaretRaster,\r
+ AffineTransform.getTranslateInstance((pCG.x - d),\r
+ canvas.getHeight() - (pCG.y + d)));\r
+ } else {\r
+ og2d.drawRenderedImage(\r
+ cgCaretRaster,\r
+ AffineTransform.getTranslateInstance((pCG.x - d),\r
+ canvas.getHeight() - (pCG.y + d)));\r
+ og2d.drawRenderedImage(\r
+ cpCaretRaster,\r
+ AffineTransform.getTranslateInstance((pCP.x - d),\r
+ canvas.getHeight() - (pCP.y + d)));\r
+ }\r
+ og2d.dispose();\r
+ \r
+ gl.glEnable(GL.GL_BLEND);\r
+ caretOverlay.drawAll();\r
+ gl.glDisable(GL.GL_BLEND);\r
+ }\r
+ \r
+ /**\r
+ * Draw the extras overlay to the gl canvas.\r
+ * Re-blits the overlay every frame. Only re-renders the overlay\r
+ * when needed.\r
+ */\r
+ private void drawExtras(GL2 gl, GLU glu){\r
+ //Only re-render if needed\r
+ // redrawExtras: Some external change (new simulation data) means\r
+ // the data is out of date.\r
+ // extrasOverlay.contentsLost(): For some reason the buffer with this\r
+ // data is lost.\r
+ if ( redrawExtras || extrasOverlay.contentsLost() ){\r
+ log.debug("Redrawing Overlay");\r
+ \r
+ final Graphics2D og2d = extrasOverlay.createGraphics(); \r
+ setRenderingHints(og2d);\r
+\r
+ og2d.setBackground(new Color(0, 0, 0, 0));\r
+ og2d.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());\r
+ extrasOverlay.markDirty(0, 0, canvas.getWidth(), canvas.getHeight());\r
+ \r
+ for (FigureElement e : relativeExtra) {\r
+ e.paint(og2d, 1);\r
+ }\r
+ Rectangle rect = this.getVisibleRect();\r
+ \r
+ for (FigureElement e : absoluteExtra) {\r
+ e.paint(og2d, 1.0, rect);\r
+ }\r
+ og2d.dispose();\r
+ \r
+ redrawExtras = false;\r
+ }\r
+\r
+ //Re-blit to gl canvas every time\r
+ gl.glEnable(GL.GL_BLEND);\r
+ extrasOverlay.drawAll();\r
+ gl.glDisable(GL.GL_BLEND);\r
+ }\r
+\r
+ @Override\r
+ public void dispose(GLAutoDrawable drawable) {\r
+ }\r
+\r
+ @Override\r
+ public void init(GLAutoDrawable drawable) {\r
+ rr.init(drawable);\r
+\r
+ GL2 gl = drawable.getGL().getGL2();\r
+ gl.glClearDepth(1.0f); // clear z-buffer to the farthest\r
+\r
+ gl.glDepthFunc(GL.GL_LEQUAL); // the type of depth test to do\r
+\r
+ float amb = 0.5f;\r
+ float dif = 1.0f;\r
+ gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_AMBIENT,\r
+ new float[] { amb, amb, amb, 1 }, 0);\r
+ gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_DIFFUSE,\r
+ new float[] { dif, dif, dif, 1 }, 0);\r
+ gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_SPECULAR,\r
+ new float[] { dif, dif, dif, 1 }, 0);\r
+\r
+ gl.glEnable(GLLightingFunc.GL_LIGHT1);\r
+ gl.glEnable(GLLightingFunc.GL_LIGHTING);\r
+ gl.glShadeModel(GLLightingFunc.GL_SMOOTH);\r
+\r
+ gl.glEnable(GLLightingFunc.GL_NORMALIZE);\r
+\r
+ extrasOverlay = new Overlay(drawable);\r
+ caretOverlay = new Overlay(drawable);\r
+ }\r
+\r
+ @Override\r
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {\r
+ GL2 gl = drawable.getGL().getGL2();\r
+ GLU glu = new GLU();\r
+\r
+ double ratio = (double) w / (double) h;\r
+ fovX = fovY * ratio;\r
+\r
+ gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);\r
+ gl.glLoadIdentity();\r
+ glu.gluPerspective(fovY, ratio, 0.05f, 100f);\r
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+ \r
+ redrawExtras = true;\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private static class Bounds {\r
+ double xMin, xMax, xSize;\r
+ double yMin, yMax, ySize;\r
+ double zMin, zMax, zSize;\r
+ double rMax;\r
+ }\r
+\r
+ /**\r
+ * Calculates the bounds for the current configuration\r
+ * \r
+ * @return\r
+ */\r
+ private Bounds calculateBounds() {\r
+ Bounds ret = new Bounds();\r
+ Collection<Coordinate> bounds = configuration.getBounds();\r
+ for (Coordinate c : bounds) {\r
+ ret.xMax = Math.max(ret.xMax, c.x);\r
+ ret.xMin = Math.min(ret.xMin, c.x);\r
+\r
+ ret.yMax = Math.max(ret.yMax, c.y);\r
+ ret.yMin = Math.min(ret.yMin, c.y);\r
+\r
+ ret.zMax = Math.max(ret.zMax, c.z);\r
+ ret.zMin = Math.min(ret.zMin, c.z);\r
+\r
+ double r = MathUtil.hypot(c.y, c.z);\r
+ ret.rMax = Math.max(ret.rMax, r);\r
+ }\r
+ ret.xSize = ret.xMax - ret.xMin;\r
+ ret.ySize = ret.yMax - ret.yMin;\r
+ ret.zSize = ret.zMax - ret.zMin;\r
+ return ret;\r
+ }\r
+\r
+ private void setupView(GL2 gl, GLU glu) {\r
+ gl.glLoadIdentity();\r
+\r
+ gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION,\r
+ lightPosition, 0);\r
+\r
+ // Get the bounds\r
+ Bounds b = calculateBounds();\r
+\r
+ // Calculate the distance needed to fit the bounds in both the X and Y\r
+ // direction\r
+ // Add 10% for space around it.\r
+ double dX = (b.xSize * 1.2 / 2.0)\r
+ / Math.tan(Math.toRadians(fovX / 2.0));\r
+ double dY = (b.rMax * 2.0 * 1.2 / 2.0)\r
+ / Math.tan(Math.toRadians(fovY / 2.0));\r
+\r
+ // Move back the greater of the 2 distances\r
+ glu.gluLookAt(0, 0, Math.max(dX, dY), 0, 0, 0, 0, 1, 0);\r
+\r
+ gl.glRotated(yaw * (180.0 / Math.PI), 0, 1, 0);\r
+ gl.glRotated(roll * (180.0 / Math.PI), 1, 0, 0);\r
+\r
+ // Center the rocket in the view.\r
+ gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0);\r
+ \r
+ //Change to LEFT Handed coordinates\r
+ gl.glScaled(1, 1, -1);\r
+ gl.glFrontFace(GL.GL_CW);\r
+ \r
+ //Flip textures for LEFT handed coords\r
+ gl.glMatrixMode(GL.GL_TEXTURE);\r
+ gl.glLoadIdentity();\r
+ gl.glScaled(-1,1,1);\r
+ gl.glTranslated(-1,0,0);\r
+ gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+ }\r
+\r
+ /**\r
+ * Call when the rocket has changed\r
+ */\r
+ public void updateFigure() {\r
+ log.debug("3D Figure Updated");\r
+ rr.updateFigure();\r
+ internalRepaint();\r
+ }\r
+\r
+ private void internalRepaint(){\r
+ super.repaint();\r
+ if (canvas != null)\r
+ canvas.display();\r
+ }\r
+ \r
+ @Override\r
+ public void repaint() {\r
+ redrawExtras = true;\r
+ internalRepaint();\r
+ }\r
+\r
+ private Set<RocketComponent> selection = new HashSet<RocketComponent>();\r
+\r
+ public void setSelection(RocketComponent[] selection) {\r
+ this.selection.clear();\r
+ if (selection != null) {\r
+ for (RocketComponent c : selection)\r
+ this.selection.add(c);\r
+ }\r
+ internalRepaint();\r
+ }\r
+\r
+ private void setRoll(double rot) {\r
+ if (MathUtil.equals(roll, rot))\r
+ return;\r
+ this.roll = MathUtil.reduce360(rot);\r
+ internalRepaint();\r
+ }\r
+\r
+ private void setYaw(double rot) {\r
+ if (MathUtil.equals(yaw, rot))\r
+ return;\r
+ this.yaw = MathUtil.reduce360(rot);\r
+ internalRepaint();\r
+ }\r
+\r
+ // ///////////// Extra methods\r
+\r
+ private Coordinate project(Coordinate c, GL2 gl, GLU glu) {\r
+ double[] mvmatrix = new double[16];\r
+ double[] projmatrix = new double[16];\r
+ int[] viewport = new int[4];\r
+\r
+ gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);\r
+ gl.glGetDoublev(GLMatrixFunc.GL_MODELVIEW_MATRIX, mvmatrix, 0);\r
+ gl.glGetDoublev(GLMatrixFunc.GL_PROJECTION_MATRIX, projmatrix, 0);\r
+\r
+ double out[] = new double[4];\r
+ glu.gluProject(c.x, c.y, c.z, mvmatrix, 0, projmatrix, 0, viewport, 0,\r
+ out, 0);\r
+\r
+ return new Coordinate(out[0], out[1], out[2]);\r
+ }\r
+\r
+ private Coordinate cp = new Coordinate(0, 0, 0);\r
+ private Coordinate cg = new Coordinate(0, 0, 0);\r
+\r
+ public void setCG(Coordinate cg) {\r
+ this.cg = cg;\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void setCP(Coordinate cp) {\r
+ this.cp = cp;\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void addRelativeExtra(FigureElement p) {\r
+ relativeExtra.add(p);\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void removeRelativeExtra(FigureElement p) {\r
+ relativeExtra.remove(p);\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void clearRelativeExtra() {\r
+ relativeExtra.clear();\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void addAbsoluteExtra(FigureElement p) {\r
+ absoluteExtra.add(p);\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void removeAbsoluteExtra(FigureElement p) {\r
+ absoluteExtra.remove(p);\r
+ redrawExtras = true;\r
+ }\r
+\r
+ public void clearAbsoluteExtra() {\r
+ absoluteExtra.clear();\r
+ redrawExtras = true;\r
+ }\r
+\r
+ private ComponentSelectionListener csl;\r
+\r
+ public static interface ComponentSelectionListener {\r
+ public void componentClicked(RocketComponent[] components, MouseEvent e);\r
+ }\r
+\r
+ public void addComponentSelectionListener(\r
+ ComponentSelectionListener newListener) {\r
+ this.csl = newListener;\r
+ }\r
+\r
+}\r
--- /dev/null
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.awt.Point;\r
+import java.nio.ByteBuffer;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+import java.util.Vector;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GL2ES1;\r
+import javax.media.opengl.GL2GL3;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+\r
+import net.sf.openrocket.motor.Motor;\r
+import net.sf.openrocket.rocketcomponent.BodyTube;\r
+import net.sf.openrocket.rocketcomponent.Configuration;\r
+import net.sf.openrocket.rocketcomponent.ExternalComponent;\r
+import net.sf.openrocket.rocketcomponent.MotorMount;\r
+import net.sf.openrocket.rocketcomponent.NoseCone;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.rocketcomponent.SymmetricComponent;\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Color;\r
+import net.sf.openrocket.util.Coordinate;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class RocketRenderer {\r
+ ComponentRenderer cr;\r
+\r
+ private final float[] selectedEmissive = { 1, 0, 0, 1 };\r
+ private final float[] colorBlack = { 0, 0, 0, 1 };\r
+ private final float[] color = new float[4];\r
+\r
+ public void init(GLAutoDrawable drawable) {\r
+ cr = new ComponentRenderer();\r
+ cr.init(drawable);\r
+ }\r
+ \r
+ public void updateFigure() {\r
+ cr.updateFigure();\r
+ }\r
+\r
+ private boolean isDrawn(RocketComponent c) {\r
+ return true;\r
+ }\r
+\r
+ private boolean isDrawnTransparent(RocketComponent c) {\r
+ if (c instanceof BodyTube)\r
+ return true;\r
+ if (c instanceof NoseCone)\r
+ return false;\r
+ if (c instanceof SymmetricComponent) {\r
+ if (((SymmetricComponent) c).isFilled())\r
+ return false;\r
+ }\r
+ if (c instanceof Transition) {\r
+ Transition t = (Transition) c;\r
+ return !t.isAftShoulderCapped() && !t.isForeShoulderCapped();\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public RocketComponent pick(GLAutoDrawable drawable,\r
+ Configuration configuration, Point p, Set<RocketComponent> ignore) {\r
+ final GL2 gl = drawable.getGL().getGL2();\r
+ gl.glEnable(GL.GL_DEPTH_TEST);\r
+ \r
+ //Store a vector of pickable parts.\r
+ final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();\r
+ \r
+ for (RocketComponent c : configuration) {\r
+ if ( ignore != null && ignore.contains(c) )\r
+ continue;\r
+\r
+ //Encode the index of the part as a color\r
+ //if index is 0x0ABC the color ends up as\r
+ //0xA0B0C000 with each nibble in the coresponding\r
+ //high bits of the RG and B channels.\r
+ gl.glColor4ub((byte) ((pickParts.size() >> 4) & 0xF0),\r
+ (byte) ((pickParts.size() << 0) & 0xF0),\r
+ (byte) ((pickParts.size() << 4) & 0xF0), (byte) 1);\r
+ pickParts.add(c);\r
+ \r
+ if (isDrawnTransparent(c)) {\r
+ gl.glEnable(GL.GL_CULL_FACE);\r
+ gl.glCullFace(GL.GL_FRONT);\r
+ cr.renderGeometry(gl, c);\r
+ gl.glDisable(GL.GL_CULL_FACE);\r
+ } else {\r
+ cr.renderGeometry(gl, c);\r
+ }\r
+ }\r
+\r
+ ByteBuffer bb = ByteBuffer.allocateDirect(4);\r
+\r
+ gl.glReadPixels(p.x, p.y, 1, 1, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, bb);\r
+\r
+ final int pickColor = bb.getInt();\r
+ final int pickIndex = ((pickColor >> 20) & 0xF00) | ((pickColor >> 16) & 0x0F0)\r
+ | ((pickColor >> 12) & 0x00F);\r
+\r
+ if ( pickIndex < 0 || pickIndex > pickParts.size() - 1 )\r
+ return null;\r
+ \r
+ return pickParts.get(pickIndex);\r
+ }\r
+\r
+ public void render(GLAutoDrawable drawable, Configuration configuration,\r
+ Set<RocketComponent> selection) {\r
+ if (cr == null)\r
+ throw new IllegalStateException(this + " Not Initialized");\r
+\r
+ GL2 gl = drawable.getGL().getGL2();\r
+\r
+ gl.glEnable(GL.GL_DEPTH_TEST); // enables depth testing\r
+ gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);\r
+\r
+ // Draw all inner components\r
+ for (RocketComponent c : configuration) {\r
+ if (isDrawn(c)) {\r
+ if (!isDrawnTransparent(c)) {\r
+ renderComponent(gl, c, 1.0f);\r
+ }\r
+ }\r
+ }\r
+\r
+ renderMotors(gl, configuration);\r
+\r
+ // Draw Tube and Transition back faces, blended with depth test\r
+ // so that they show up behind.\r
+ gl.glEnable(GL.GL_CULL_FACE);\r
+ gl.glCullFace(GL.GL_FRONT);\r
+ for (RocketComponent c : configuration) {\r
+ if (isDrawn(c)) {\r
+ if (isDrawnTransparent(c)) {\r
+ renderComponent(gl, c, 1.0f);\r
+ }\r
+ }\r
+ }\r
+ gl.glDisable(GL.GL_CULL_FACE);\r
+\r
+ // Draw T&T front faces blended, without depth test\r
+ gl.glEnable(GL.GL_BLEND);\r
+ gl.glEnable(GL.GL_CULL_FACE);\r
+ gl.glCullFace(GL.GL_BACK);\r
+ for (RocketComponent c : configuration) {\r
+ if (isDrawn(c)) {\r
+ if (isDrawnTransparent(c)) {\r
+ renderComponent(gl, c, 0.2f);\r
+ }\r
+ }\r
+ }\r
+ gl.glDisable(GL.GL_BLEND);\r
+ gl.glDisable(GL.GL_CULL_FACE);\r
+\r
+ gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,\r
+ selectedEmissive, 0);\r
+ gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, colorBlack, 0);\r
+ gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, colorBlack, 0);\r
+ gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0);\r
+ \r
+ gl.glDepthMask(false);\r
+ gl.glDisable(GL.GL_DEPTH_TEST);\r
+ gl.glEnable(GL.GL_STENCIL_TEST);\r
+\r
+ for (RocketComponent c : configuration) {\r
+ if (selection.contains(c)) {\r
+ // So it is faster to do this once before the loop,\r
+ // but then the outlines are not as good if you multi-select.\r
+ // Not sure which to do.\r
+\r
+ gl.glStencilMask(1);\r
+ gl.glDisable(GL.GL_SCISSOR_TEST);\r
+ gl.glClearStencil(0);\r
+ gl.glClear(GL.GL_STENCIL_BUFFER_BIT);\r
+ gl.glStencilMask(0);\r
+\r
+ gl.glStencilFunc(GL.GL_ALWAYS, 1, 1);\r
+ gl.glStencilMask(1);\r
+ gl.glColorMask(false, false, false, false);\r
+ gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);\r
+ gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_REPLACE);\r
+ cr.renderGeometry(gl, c);\r
+ gl.glStencilMask(0);\r
+\r
+ gl.glColorMask(true, true, true, true);\r
+ gl.glStencilFunc(GL.GL_NOTEQUAL, 1, 1);\r
+ gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE);\r
+ gl.glLineWidth(5.0f);\r
+ cr.renderGeometry(gl, c);\r
+ }\r
+ }\r
+ gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);\r
+ gl.glDepthMask(true);\r
+ gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,\r
+ colorBlack, 0);\r
+ gl.glDisable(GL.GL_STENCIL_TEST);\r
+ gl.glEnable(GL.GL_DEPTH_TEST);\r
+ }\r
+\r
+ private void renderMotors(GL2 gl, Configuration configuration) {\r
+ String motorID = configuration.getMotorConfigurationID();\r
+ Iterator<MotorMount> iterator = configuration.motorIterator();\r
+ while (iterator.hasNext()) {\r
+ MotorMount mount = iterator.next();\r
+ Motor motor = mount.getMotor(motorID);\r
+ double length = motor.getLength();\r
+ double radius = motor.getDiameter() / 2;\r
+\r
+ Coordinate[] position = ((RocketComponent) mount)\r
+ .toAbsolute(new Coordinate(((RocketComponent) mount)\r
+ .getLength() + mount.getMotorOverhang() - length));\r
+\r
+ for (int i = 0; i < position.length; i++) {\r
+ cr.renderMotor(gl, position[i], length, radius);\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ \r
+ public void renderComponent(GL2 gl, RocketComponent c, float alpha) {\r
+ gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1);\r
+\r
+ getOutsideColor(c, alpha, color);\r
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0);\r
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0);\r
+\r
+ getSpecularColor(c, alpha, color);\r
+ gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0);\r
+ gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS,\r
+ getShininess(c));\r
+\r
+ getInsideColor(c, alpha, color);\r
+ gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0);\r
+ gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0);\r
+\r
+ cr.renderGeometry(gl, c);\r
+ }\r
+\r
+ private int getShininess(RocketComponent c) {\r
+ if (c instanceof ExternalComponent) {\r
+ switch (((ExternalComponent) c).getFinish()) {\r
+ case ROUGH:\r
+ return 10;\r
+ case UNFINISHED:\r
+ return 30;\r
+ case NORMAL:\r
+ return 40;\r
+ case SMOOTH:\r
+ return 80;\r
+ case POLISHED:\r
+ return 128;\r
+ }\r
+ return 100;\r
+ } else {\r
+ return 20;\r
+ }\r
+ }\r
+\r
+ private void getSpecularColor(RocketComponent c, float alpha, float[] out) {\r
+ int shine = getShininess(c);\r
+ float m = (float) shine / 128.0f;\r
+ float d = 0.9f;\r
+ getOutsideColor(c, alpha, out);\r
+ out[0] = Math.max(out[0], d) * m;\r
+ out[1] = Math.max(out[1], d) * m;\r
+ out[2] = Math.max(out[2], d) * m;\r
+ }\r
+\r
+ private void getInsideColor(RocketComponent c, float alpha, float[] out) {\r
+ float d = 0.4f;\r
+ getOutsideColor(c, alpha, out);\r
+ out[0] *= d;\r
+ out[1] *= d;\r
+ out[2] *= d;\r
+ }\r
+\r
+ private HashMap<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, Color>();\r
+ private void getOutsideColor(RocketComponent c, float alpha, float[] out) {\r
+ Color col;\r
+ col = c.getColor();\r
+ if (col == null){\r
+ if ( defaultColorCache.containsKey(c.getClass()) ){\r
+ col = defaultColorCache.get(c.getClass());\r
+ } else {\r
+ col = Application.getPreferences().getDefaultColor(c.getClass());\r
+ defaultColorCache.put(c.getClass(), col);\r
+ }\r
+ }\r
+ \r
+ out[0] = Math.max(0.2f, (float) col.getRed() / 255f);\r
+ out[1] = Math.max(0.2f, (float) col.getGreen() / 255f);\r
+ out[2] = Math.max(0.2f, (float) col.getBlue() / 255f);\r
+ out[3] = alpha;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ ** License Applicability. Except to the extent portions of this file are\r
+ ** made subject to an alternative license as permitted in the SGI Free\r
+ ** Software License B, Version 2.0 (the "License"), the contents of this\r
+ ** file are subject only to the provisions of the License. You may not use\r
+ ** this file except in compliance with the License. You may obtain a copy\r
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\r
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\r
+ ** \r
+ ** http://oss.sgi.com/projects/FreeB\r
+ ** \r
+ ** Note that, as provided in the License, the Software is distributed on an\r
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\r
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\r
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\r
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\r
+ ** \r
+ ** NOTE: The Original Code (as defined below) has been licensed to Sun\r
+ ** Microsystems, Inc. ("Sun") under the SGI Free Software License B\r
+ ** (Version 1.1), shown above ("SGI License"). Pursuant to Section\r
+ ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to\r
+ ** you under an alternative license ("Alternative License"). This\r
+ ** Alternative License includes all of the provisions of the SGI License\r
+ ** except that Section 2.2 and 11 are omitted. Any differences between\r
+ ** the Alternative License and the SGI License are offered solely by Sun\r
+ ** and not by SGI.\r
+ **\r
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,\r
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\r
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.\r
+ ** Copyright in any portions created by third parties is as indicated\r
+ ** elsewhere herein. All Rights Reserved.\r
+ ** \r
+ ** Additional Notice Provisions: The application programming interfaces\r
+ ** established by SGI in conjunction with the Original Code are The\r
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released\r
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version\r
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X\r
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software\r
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation\r
+ ** published by SGI, but has not been independently verified as being\r
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.\r
+ **\r
+ ** $Date: 2009-03-04 17:23:34 -0800 (Wed, 04 Mar 2009) $ $Revision: 1856 $\r
+ ** $Header$\r
+ */\r
+\r
+/* \r
+ * Copyright (c) 2002-2004 LWJGL Project\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are \r
+ * met:\r
+ * \r
+ * * Redistributions of source code must retain the above copyright \r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of 'LWJGL' nor the names of \r
+ * its contributors may be used to endorse or promote products derived \r
+ * from this software without specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, \r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR \r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING \r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are\r
+ * met:\r
+ * \r
+ * - Redistribution of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * - Redistribution in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * \r
+ * Neither the name of Sun Microsystems, Inc. or the names of\r
+ * contributors may be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ * \r
+ * This software is provided "AS IS," without a warranty of any kind. ALL\r
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,\r
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A\r
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN\r
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR\r
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR\r
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR\r
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR\r
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE\r
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,\r
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF\r
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r
+ * \r
+ * You acknowledge that this software is not designed or intended for use\r
+ * in the design, construction, operation or maintenance of any nuclear\r
+ * facility.\r
+ */\r
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+\r
+public final class TransitionRenderer {\r
+ private static final boolean textureFlag = true;\r
+\r
+ private TransitionRenderer() {\r
+ }\r
+\r
+ public static final void drawTransition(final GL2 gl, final Transition tr,\r
+ final int slices, final int stacks) {\r
+\r
+ double da, r, dz;\r
+ double x, y, z, nz, nsign;\r
+ int i, j;\r
+\r
+ nsign = 1.0f;\r
+\r
+ da = 2.0f * PI / slices;\r
+ dz = (double) tr.getLength() / stacks;\r
+\r
+ double ds = 1.0f / slices;\r
+ double dt = 1.0f / stacks;\r
+ double t = 0.0f;\r
+ z = 0.0f;\r
+ r = (double) tr.getForeRadius();\r
+ for (j = 0; j < stacks; j++) {\r
+ r = (double) tr.getRadius(z);\r
+ double rNext = (double) tr.getRadius(z + dz);\r
+\r
+ if (j == stacks - 1)\r
+ rNext = (double) tr.getRadius(tr.getLength());\r
+\r
+ // Z component of normal vectors\r
+ nz = -(rNext - r) / dz;\r
+\r
+ double s = 0.0f;\r
+ glBegin(gl, GL2.GL_QUAD_STRIP);\r
+ for (i = 0; i <= slices; i++) {\r
+ if (i == slices) {\r
+ x = sin(0.0f);\r
+ y = cos(0.0f);\r
+ } else {\r
+ x = sin((i * da));\r
+ y = cos((i * da));\r
+ }\r
+ if (nsign == 1.0f) {\r
+ normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+ TXTR_COORD(gl, s, t);\r
+ glVertex3d(gl, (x * r), (y * r), z);\r
+ normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+ TXTR_COORD(gl, s, t + dt);\r
+ glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+ } else {\r
+ normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+ TXTR_COORD(gl, s, t);\r
+ glVertex3d(gl, (x * r), (y * r), z);\r
+ normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+ TXTR_COORD(gl, s, t + dt);\r
+ glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+ }\r
+ s += ds;\r
+ } // for slices\r
+ glEnd(gl);\r
+ // r += dr;\r
+ t += dt;\r
+ z += dz;\r
+ } // for stacks\r
+\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // Internals only below this point\r
+ //\r
+\r
+ private static final double PI = (double) Math.PI;\r
+\r
+ private static final void glBegin(GL gl, int mode) {\r
+ gl.getGL2().glBegin(mode);\r
+ }\r
+\r
+ private static final void glEnd(GL gl) {\r
+ gl.getGL2().glEnd();\r
+ }\r
+\r
+ private static final void glVertex3d(GL gl, double x, double y, double z) {\r
+ gl.getGL2().glVertex3d(x, y, z);\r
+ }\r
+\r
+ private static final void glNormal3d(GL gl, double x, double y, double z) {\r
+ gl.getGL2().glNormal3d(x, y, z);\r
+ }\r
+\r
+ private static final void glTexCoord2d(GL gl, double x, double y) {\r
+ gl.getGL2().glTexCoord2d(x, y);\r
+ }\r
+\r
+ /**\r
+ * Call glNormal3f after scaling normal to unit length.\r
+ * \r
+ * @param x\r
+ * @param y\r
+ * @param z\r
+ */\r
+ private static final void normal3d(GL gl, double x, double y, double z) {\r
+ double mag;\r
+\r
+ mag = (double) Math.sqrt(x * x + y * y + z * z);\r
+ if (mag > 0.00001F) {\r
+ x /= mag;\r
+ y /= mag;\r
+ z /= mag;\r
+ }\r
+ glNormal3d(gl, x, y, z);\r
+ }\r
+\r
+ private static final void TXTR_COORD(GL gl, double x, double y) {\r
+ if (textureFlag)\r
+ glTexCoord2d(gl, x, y);\r
+ }\r
+\r
+ private static final double sin(double r) {\r
+ return (double) Math.sin(r);\r
+ }\r
+\r
+ private static final double cos(double r) {\r
+ return (double) Math.cos(r);\r
+ }\r
+}\r
package net.sf.openrocket.gui.scalefigure;
+import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import javax.swing.AbstractAction;
import javax.swing.Action;
+import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.sf.openrocket.gui.components.StageSelector;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
+import net.sf.openrocket.gui.figure3d.RocketFigure3d;
import net.sf.openrocket.gui.figureelements.CGCaret;
import net.sf.openrocket.gui.figureelements.CPCaret;
import net.sf.openrocket.gui.figureelements.Caret;
* A JPanel that contains a RocketFigure and buttons to manipulate the figure.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ * @author Bill Kuker <bkuker@billkuker.com>
*/
public class RocketPanel extends JPanel implements TreeSelectionListener, ChangeSource {
-
+ private static final long serialVersionUID = 1L;
+
private static final Translator trans = Application.getTranslator();
+
+ private boolean is3d;
private final RocketFigure figure;
+ private final RocketFigure3d figure3d;
+
+
private final ScaleScrollPane scrollPane;
+ private final JPanel figureHolder;
+
private JLabel infoMessage;
private TreeSelectionModel selectionModel = null;
+ private BasicSlider rotationSlider;
+ ScaleSelector scaleSelector;
+
/* Calculation of CP and CG */
private AerodynamicCalculator aerodynamicCalculator;
// Create figure and custom scroll pane
figure = new RocketFigure(configuration);
+ figure3d = new RocketFigure3d(configuration);
+
+ figureHolder = new JPanel(new BorderLayout());
scrollPane = new ScaleScrollPane(figure) {
+ private static final long serialVersionUID = 1L;
+
@Override
public void mouseClicked(MouseEvent event) {
handleMouseClick(event);
createPanel();
+ is3d = true;
+ go2D();
+
configuration.addChangeListener(new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
// System.out.println("Configuration changed, calling updateFigure");
updateExtras();
- figure.updateFigure();
+ updateFigures();
+ }
+ });
+
+ figure3d.addComponentSelectionListener(new RocketFigure3d.ComponentSelectionListener() {
+ @Override
+ public void componentClicked(RocketComponent clicked[], MouseEvent event) {
+ handleComponentClick(clicked, event);
}
});
}
+ private void updateFigures() {
+ if (!is3d)
+ figure.updateFigure();
+ else
+ figure3d.updateFigure();
+ }
+
+ private void go3D() {
+ if (is3d)
+ return;
+ is3d = true;
+ figureHolder.remove(scrollPane);
+ figureHolder.add(figure3d, BorderLayout.CENTER);
+ rotationSlider.setEnabled(false);
+ scaleSelector.setEnabled(false);
+
+ revalidate();
+ figureHolder.revalidate();
+
+ figure3d.repaint();
+ }
+
+ private void go2D() {
+ if (!is3d)
+ return;
+ is3d = false;
+ figureHolder.remove(figure3d);
+ figureHolder.add(scrollPane, BorderLayout.CENTER);
+ rotationSlider.setEnabled(true);
+ scaleSelector.setEnabled(true);
+ revalidate();
+ figureHolder.revalidate();
+ figure.repaint();
+ }
/**
* Creates the layout and components of the panel.
//// Create toolbar
+ ButtonGroup bg = new ButtonGroup();
+
// Side/back buttons
FigureTypeAction action = new FigureTypeAction(RocketFigure.TYPE_SIDE);
//// Side view
//// Side view
action.putValue(Action.SHORT_DESCRIPTION, trans.get("RocketPanel.FigTypeAct.ttip.Sideview"));
JToggleButton toggle = new JToggleButton(action);
+ bg.add(toggle);
add(toggle, "spanx, split");
action = new FigureTypeAction(RocketFigure.TYPE_BACK);
//// Back view
action.putValue(Action.SHORT_DESCRIPTION, trans.get("RocketPanel.FigTypeAct.ttip.Backview"));
toggle = new JToggleButton(action);
+ bg.add(toggle);
add(toggle, "gap rel");
+ //// 3d Toggle
+ final JToggleButton toggle3d = new JToggleButton(new AbstractAction("3D") {
+ private static final long serialVersionUID = 1L;
+ {
+ putValue(Action.NAME, "3D");//TODO
+ putValue(Action.SHORT_DESCRIPTION, "3D"); //TODO
+ }
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if ( ((JToggleButton)e.getSource()).isSelected() ){
+ go3D();
+ } else {
+ go2D();
+ }
+ }
+ });
+ bg.add(toggle3d);
+ add(toggle3d, "gap rel");
+
// Zoom level selector
- ScaleSelector scaleSelector = new ScaleSelector(scrollPane);
+ scaleSelector = new ScaleSelector(scrollPane);
add(scaleSelector);
add(us, "alignx 50%, growx");
// Add the rocket figure
- add(scrollPane, "grow, spany 2, wmin 300lp, hmin 100lp, wrap");
+ add(figureHolder, "grow, spany 2, wmin 300lp, hmin 100lp, wrap");
// Add rotation slider
JLabel l = new JLabel("360" + Chars.DEGREE);
Dimension d = l.getPreferredSize();
- add(new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true),
+ add(rotationSlider = new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true),
"ax 50%, wrap, width " + (d.width + 6) + "px:null:null, growy");
return;
cpAOA = aoa;
updateExtras();
- figure.updateFigure();
+ updateFigures();
fireChangeEvent();
}
if (!Double.isNaN(theta))
figure.setRotation(theta);
updateExtras();
- figure.updateFigure();
+ updateFigures();
fireChangeEvent();
}
return;
cpMach = mach;
updateExtras();
- figure.updateFigure();
+ updateFigures();
fireChangeEvent();
}
return;
cpRoll = roll;
updateExtras();
- figure.updateFigure();
+ updateFigures();
fireChangeEvent();
}
RocketComponent[] clicked = figure.getComponentsByPoint(x, y);
+ handleComponentClick(clicked, event);
+ }
+
+ private void handleComponentClick(RocketComponent[] clicked, MouseEvent event){
+
// If no component is clicked, do nothing
if (clicked.length == 0)
return;
else
cgx = Double.NaN;
+ figure3d.setCG(cg);
+ figure3d.setCP(cp);
+
// Length bound is assumed to be tight
double length = 0, diameter = 0;
Collection<Coordinate> bounds = configuration.getBounds();
extraText.setFlightData(simulation.getSimulatedData());
extraText.setCalculatingData(false);
figure.repaint();
+ figure3d.repaint();
}
@Override
extraText.setFlightData(FlightData.NaN_DATA);
extraText.setCalculatingData(false);
figure.repaint();
+ figure3d.repaint();
}
}
* Adds the extra data to the figure. Currently this includes the CP and CG carets.
*/
private void addExtras() {
- figure.clearRelativeExtra();
extraCG = new CGCaret(0, 0);
extraCP = new CPCaret(0, 0);
extraText = new RocketInfo(configuration);
updateExtras();
+
+ figure.clearRelativeExtra();
figure.addRelativeExtra(extraCP);
figure.addRelativeExtra(extraCG);
figure.addAbsoluteExtra(extraText);
+
+
+ figure3d.clearRelativeExtra();
+ //figure3d.addRelativeExtra(extraCP);
+ //figure3d.addRelativeExtra(extraCG);
+ figure3d.addAbsoluteExtra(extraText);
+
}
for (int i = 0; i < paths.length; i++)
components[i] = (RocketComponent) paths[i].getLastPathComponent();
figure.setSelection(components);
+
+ figure3d.setSelection(components);
}
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
private class FigureTypeAction extends AbstractAction implements StateChangeListener {
+ private static final long serialVersionUID = 1L;
private final int type;
public FigureTypeAction(int type) {
if (state == true) {
// This view has been selected
figure.setType(type);
+ go2D();
updateExtras();
}
stateChanged(null);
@Override
public void stateChanged(EventObject e) {
- putValue(Action.SELECTED_KEY, figure.getType() == type);
+ putValue(Action.SELECTED_KEY, figure.getType() == type && !is3d);
}
}
package net.sf.openrocket.gui.scalefigure;
+import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
return scale * 1.5;
}
+ @Override
+ public void setEnabled(boolean b){
+ for ( Component c : getComponents() ){
+ c.setEnabled(b);
+ }
+ super.setEnabled(b);
+ }
+
}
*/
public static File getCurrentJarFile() {
// Find the jar file this class is contained in
+
URL jarUrl = null;
- CodeSource codeSource = Database.class.getProtectionDomain().getCodeSource();
+ CodeSource codeSource;
+ try {
+ codeSource = new URL("rsrc:.").openConnection().getClass().getProtectionDomain().getCodeSource();
+ } catch (Throwable e) {
+ codeSource = Database.class.getProtectionDomain().getCodeSource();
+ }
+
if (codeSource != null)
jarUrl = codeSource.getLocation();