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