diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index b0a0829b7..366b86588 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -673,9 +673,6 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona // (Iyy / M + Izz / M) / 2 = (h^2 + 2 * w^2)/24 final double inertia = (h2 + 2 * w2) / 24; - System.out.println("component " + this); - System.out.println("finCount " + finCount); - System.out.println("inertia " + inertia); if (finCount == 1) return inertia; diff --git a/swing/lib/jogl/jogl-all-natives-windows-i586 (1).jar b/swing/lib/jogl/jogl-all-natives-windows-i586 (1).jar deleted file mode 100644 index 63b5ade5a..000000000 Binary files a/swing/lib/jogl/jogl-all-natives-windows-i586 (1).jar and /dev/null differ diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java index 54c5a8d37..3058e2187 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java @@ -51,6 +51,7 @@ import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.BoundingBox; /* * @author Bill Kuker @@ -285,9 +286,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { public void display(final 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); @@ -295,6 +294,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { final FlightConfiguration configuration = rkt.getSelectedConfiguration(); if (pickPoint != null) { + gl.glDisable(GL.GL_MULTISAMPLE); gl.glDisable(GLLightingFunc.GL_LIGHTING); final RocketComponent picked = rr.pick(drawable, configuration, @@ -305,7 +305,6 @@ public class RocketFigure3d extends JPanel implements GLEventListener { @Override public void run() { if (picked == null) { - log.debug("unselecting"); csl.componentClicked(new RocketComponent[] {}, e); } else { csl.componentClicked(new RocketComponent[] { picked }, e); @@ -318,7 +317,8 @@ public class RocketFigure3d extends JPanel implements GLEventListener { gl.glClearColor(1, 1, 1, 1); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - + + gl.glEnable(GL.GL_MULTISAMPLE); gl.glEnable(GLLightingFunc.GL_LIGHTING); } rr.render(drawable, configuration, selection); @@ -326,7 +326,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { drawExtras(gl, glu); drawCarets(gl, glu); - //GLJPanel with GLSL Flipper relies on this: + // GLJPanel with GLSL Flipper relies on this: gl.glFrontFace(GL.GL_CCW); } @@ -468,47 +468,19 @@ public class RocketFigure3d extends JPanel implements GLEventListener { redrawExtras = true; } - @SuppressWarnings("unused") - private static class Bounds { - double xMin, xMax, xSize; - double yMin, yMax, ySize; - double zMin, zMax, zSize; - double rMax; - } - - private Bounds cachedBounds = null; + private BoundingBox cachedBounds = null; /** * Calculates the bounds for the current configuration * * @return */ - private Bounds calculateBounds() { - if (cachedBounds != null) { - return cachedBounds; - } else { - final Bounds b = new Bounds(); + private BoundingBox calculateBounds() { + if (cachedBounds == null) { final FlightConfiguration configuration = rkt.getSelectedConfiguration(); - final Collection bounds = configuration.getBounds(); - for (Coordinate c : bounds) { - b.xMax = Math.max(b.xMax, c.x); - b.xMin = Math.min(b.xMin, c.x); - - b.yMax = Math.max(b.yMax, c.y); - b.yMin = Math.min(b.yMin, c.y); - - b.zMax = Math.max(b.zMax, c.z); - b.zMin = Math.min(b.zMin, c.z); - - double r = MathUtil.hypot(c.y, c.z); - b.rMax = Math.max(b.rMax, r); - } - b.xSize = b.xMax - b.xMin; - b.ySize = b.yMax - b.yMin; - b.zSize = b.zMax - b.zMin; - cachedBounds = b; - return b; + cachedBounds = configuration.getBoundingBox(); } + return cachedBounds; } private void setupView(final GL2 gl, final GLU glu) { @@ -516,16 +488,16 @@ public class RocketFigure3d extends JPanel implements GLEventListener { gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION, lightPosition, 0); - + // Get the bounds - final Bounds b = calculateBounds(); + final BoundingBox b = calculateBounds(); // Calculate the distance needed to fit the bounds in both the X and Y // direction // Add 10% for space around it. - final double dX = (b.xSize * 1.2 / 2.0) + final double dX = (b.span().x * 1.2 / 2.0) / Math.tan(Math.toRadians(fovX / 2.0)); - final double dY = (b.rMax * 2.0 * 1.2 / 2.0) + final double dY = (b.span().y * 2.0 * 1.2 / 2.0) / Math.tan(Math.toRadians(fovY / 2.0)); // Move back the greater of the 2 distances @@ -535,7 +507,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener { 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); + gl.glTranslated(-b.min.x - b.span().x / 2.0, 0, 0); //Change to LEFT Handed coordinates gl.glScaled(1, 1, -1); @@ -593,14 +565,14 @@ public class RocketFigure3d extends JPanel implements GLEventListener { private void setRoll(final double rot) { if (MathUtil.equals(roll, rot)) return; - this.roll = MathUtil.reduce360(rot); + this.roll = MathUtil.reduce2PI(rot); internalRepaint(); } private void setYaw(final double rot) { if (MathUtil.equals(yaw, rot)) return; - this.yaw = MathUtil.reduce360(rot); + this.yaw = MathUtil.reduce2PI(rot); internalRepaint(); } diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java index 086d2f7f1..c6aef258e 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java @@ -4,9 +4,9 @@ import java.awt.Point; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.Vector; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; @@ -59,50 +59,62 @@ public abstract class RocketRenderer { public abstract boolean isDrawnTransparent(RocketComponent c); public abstract void flushTextureCache(GLAutoDrawable drawable); - - public RocketComponent pick(GLAutoDrawable drawable, FlightConfiguration configuration, Point p, - Set ignore) { + + /** + * This function is a bit.... unusual. Instead of computing an inverse transform from the UI window into design-space, + * this renders each component with a unique identifiable color ... to a dummy, throwaway canvas: + * + * Then, we read the pixel (RGB) color value at a point on the canvas, and use that color to identify the component + * + * @param drawable canvas to draw to + * @param configuration active configuration + * @param p point to select at + * @param ignore list of ignore components + * @return optional (nullable) component selection result + */ + public RocketComponent pick(GLAutoDrawable drawable, FlightConfiguration configuration, Point p, Set ignore) { final GL2 gl = drawable.getGL().getGL2(); gl.glEnable(GL.GL_DEPTH_TEST); - + // Store a vector of pickable parts. - final Vector pickParts = new Vector(); - - for (RocketComponent c : configuration.getActiveComponents()) { - if (ignore != null && ignore.contains(c)) + final Map selectionMap = new HashMap<>(); + + Collection geometryList = getTreeGeometry( configuration); + for(Geometry geom: geometryList ) { + final RocketComponent comp = geom.getComponent(); + if (ignore != null && ignore.contains(comp)) 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)) { - cr.getComponentGeometry(c).render(gl, Surface.INSIDE); - } else { - cr.getComponentGeometry(c).render(gl, Surface.ALL); + + if( geom.active ) { + final int hashCode = comp.hashCode(); + + selectionMap.put(hashCode, comp); + + gl.glColor4ub((byte) ((hashCode >> 24) & 0xFF), // red channel (LSB) + (byte) ((hashCode >> 16) & 0xFF), // green channel + (byte) ((hashCode >> 8) & 0xFF), // blue channel + (byte) ((hashCode) & 0xFF)); // alpha channel (MSB) + + if (isDrawnTransparent(comp)) { + geom.render(gl, Surface.INSIDE); + } else { + geom.render(gl, Surface.ALL); + } } } - - ByteBuffer bb = ByteBuffer.allocateDirect(4); if (p == null) return null; //Allow pick to be called without a point for debugging - - 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); - - log.trace("Picked pixel color is {} index is {}", pickColor, pickIndex); - - if (pickIndex < 0 || pickIndex > pickParts.size() - 1) - return null; - - return pickParts.get(pickIndex); + + final ByteBuffer buffer = ByteBuffer.allocateDirect(4); + gl.glReadPixels(p.x, p.y, // coordinates of "first" pixel to read + 1, 1, // width, height of rectangle to read + GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, + buffer); // output buffer + final int pixelValue = buffer.getInt(); + final RocketComponent selected = selectionMap.get(pixelValue); + + return selected; } public void render(GLAutoDrawable drawable, FlightConfiguration configuration, Set selection) { diff --git a/swing/src/net/sf/openrocket/gui/util/GUIUtil.java b/swing/src/net/sf/openrocket/gui/util/GUIUtil.java index d4cf3b322..d4f40c862 100644 --- a/swing/src/net/sf/openrocket/gui/util/GUIUtil.java +++ b/swing/src/net/sf/openrocket/gui/util/GUIUtil.java @@ -312,8 +312,11 @@ public class GUIUtil { window.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { - log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize()); - ((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize()); + final Dimension previousWindowSize = ((SwingPreferences)Application.getPreferences()).getWindowSize(window.getClass()); + if( ! window.getSize().equals(previousWindowSize)) { + log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize()); + ((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize()); + } if (window instanceof JFrame) { if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) { log.debug("Storing maximized state of " + window.getClass().getName());