Add a 3D enabled user preference

Add 3d Crash detection that disables 3d if the application crashes during one of several touchy phases of JOGL / Native / display driver initialization.
Always make the 3D view button clickable, but there is an explanation and a button to turn 3d on if it has been disabled
This commit is contained in:
Bill Kuker 2012-09-27 14:44:04 +00:00
parent 2aa4a8d905
commit 4073246388
8 changed files with 214 additions and 19 deletions

View File

@ -1,3 +1,9 @@
2012-09-27 Bill Kuker
* Added user preference to enable/disable 3D, and crash detection to disable 3D on a crash
* Moved JOGL GL initialization earlier in initialization.
2012-09-25 Doug Pedrick
* Added preference to open last edited design file upon startup.

View File

@ -52,6 +52,8 @@ RocketPanel.FigViewAct.2D = 2D View
RocketPanel.FigViewAct.ttip.2D = 2D View
RocketPanel.FigViewAct.3D = 3D View
RocketPanel.FigViewAct.ttip.3D = 3D View
RocketPanel.3DDisabledMessage = OpenRocket's 3D capabilities have been disabled by either the user or a crash.
RocketPanel.3DDisabledMessageButton = Re-enable 3D at next application launch.
RocketPanel.lbl.Motorcfg = Motor configuration:
RocketPanel.lbl.infoMessage = <html>Click to select &nbsp;&nbsp; Shift+click to select other &nbsp;&nbsp; Double-click to edit &nbsp;&nbsp; Click+drag to move
@ -221,6 +223,7 @@ pref.dlg.but.add = Add
pref.dlg.but.reset = Reset
pref.dlg.but.checknow = Check now
pref.dlg.but.openlast = Open last design file on startup
pref.dlg.but.enable3d = Enable 3D
pref.dlg.but.defaultmetric = Default metric
pref.dlg.but.defaultimperial = Default imperial
pref.dlg.title.Preferences = Preferences

View File

@ -298,7 +298,19 @@ public class PreferencesDialog extends JDialog {
Application.getPreferences().setAutoOpenLastDesignOnStartup(autoOpenDesignFile.isSelected());
}
});
panel.add(autoOpenDesignFile);
panel.add(autoOpenDesignFile, "wrap");
final JCheckBox enable3D = new JCheckBox(trans.get("pref.dlg.but.enable3d"));
enable3D.setSelected(Application.getPreferences().is3dEnabled());
enable3D.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Application.getPreferences().set3dEnabled(enable3D.isSelected());
}
});
panel.add(enable3D);
return panel;
}

View File

@ -0,0 +1,125 @@
package net.sf.openrocket.gui.figure3d;
import java.awt.SplashScreen;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import javax.media.opengl.GLProfile;
import net.sf.openrocket.arch.SystemInfo;
import net.sf.openrocket.arch.SystemInfo.Platform;
import net.sf.openrocket.gui.main.Splash;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.startup.Application;
public class OpenGLUtils {
private static final LogHelper log = Application.getLogger();
/**
* Keep the state of 3D consistent for the entire launch, so if user enables
* 3d and opens a new window it stays disabled.
*/
private static Boolean enabledThisLaunch = null;
/**
* set true in enterDangerZone, false in exitDangerZone allows the exit
* function to return immediately if called extra times
*/
private static boolean inTheDangerZone = false;
/**
* Call this method as early as possible.
*/
public static void earlyInitialize() {
// If crash detection fails this will allow someone to disable
// the 3d preference from the command line.
if (System.getProperty("openrocket.3d.disable") != null) {
Application.getPreferences().set3dEnabled(false);
}
if (!is3dEnabled()) {
log.debug("OpenGL is disabled");
} else {
log.debug("Initializing OpenGL");
enterDangerZone();
if (SystemInfo.getPlatform() == Platform.UNIX) {
log.debug("Dismissing splash screen (Linux/Java/JOGL bug)");
// Fixes a linux / X bug: Splash must be closed before GL Init
SplashScreen splash = Splash.getSplashScreen();
if (splash != null && splash.isVisible())
splash.close();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// Intentionally Ignored
}
}
log.debug("Calling GLProfile.initSingleton()");
GLProfile.initSingleton();
exitDangerZone();
}
}
/**
* Returns true if 3d functions are enabled
*
* @return
*/
static boolean is3dEnabled() {
if (enabledThisLaunch == null)
enabledThisLaunch = new Boolean(Application.getPreferences().is3dEnabled());
return enabledThisLaunch.booleanValue();
}
/**
* Signal that we are about to do something that can cause a GL crash. If
* exitDangerZone is not called after this the 3D user preference will be
* disabled at the next startup.
*/
static void enterDangerZone() {
log.verbose("Entering GL DangerZone");
inTheDangerZone = true;
Application.getPreferences().set3dEnabled(false);
try {
Preferences.userRoot().flush();
} catch (BackingStoreException e) {
log.warn("Unable to flush prefs in enterDangerZone()");
}
}
/**
* Signal that some GL operation has succeeded. the UserPreference will be
* left alone.
*
* Safe to call when not in the danger-zone. Safe to call quite often
*/
static void exitDangerZone() {
if (!inTheDangerZone)
return;
inTheDangerZone = false;
log.verbose("Exiting GL DangerZone");
Application.getPreferences().set3dEnabled(true);
try {
Preferences.userRoot().flush();
} catch (BackingStoreException e) {
log.warn("Unable to flush prefs in exitDangerZone()");
}
}
/**
* Seriously never call this it will segfault the JVM.
@Deprecated
static void segfault(){
try {
log.error("Segfaulting!");
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe)f.get(null);
unsafe.putAddress(0, 0);
} catch (Exception e) {
log.error("Unable to segfault", e);
}
}
**/
}

View File

@ -6,7 +6,10 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.SplashScreen;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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;
@ -25,16 +28,18 @@ 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.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import net.miginfocom.swing.MigLayout;
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.gui.main.Splash;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.RocketComponent;
@ -50,6 +55,7 @@ import com.jogamp.opengl.util.awt.Overlay;
public class RocketFigure3d extends JPanel implements GLEventListener {
private static final long serialVersionUID = 1L;
private static final LogHelper log = Application.getLogger();
private static final Translator trans = Application.getTranslator();
static {
//this allows the GL canvas and things like the motor selection
@ -64,8 +70,6 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
private Configuration configuration;
private GLCanvas canvas;
private Overlay extrasOverlay, caretOverlay;
private BufferedImage cgCaretRaster, cpCaretRaster;
private volatile boolean redrawExtras = true;
@ -88,27 +92,49 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
this.setLayout(new BorderLayout());
//Only initizlize GL if 3d is enabled.
if (is3dEnabled()) {
//Fixes a linux / X bug: Splash must be closed before GL Init
SplashScreen splash = Splash.getSplashScreen();
if (splash != null && splash.isVisible())
splash.close();
if ( OpenGLUtils.is3dEnabled() ){
initGLCanvas();
addHierarchyListener(new HierarchyListener(){
@Override
public void hierarchyChanged(HierarchyEvent e) {
OpenGLUtils.enterDangerZone();
RocketFigure3d.this.removeHierarchyListener(this);
}
});
} else {
setupDisabledUI();
}
}
/**
* Return true if 3d view is enabled. This may be toggled by the user at
* launch time.
* @return
* Draws a pretty primitive UI that explains that 3D is not enabled.
*/
public static boolean is3dEnabled() {
return System.getProperty("openrocket.3d.disable") == null;
private void setupDisabledUI(){
canvas = null;
final JPanel panel = new JPanel(new MigLayout("filly"));
panel.add(new JLabel(trans.get("RocketPanel.3DDisabledMessage")));
if ( !Application.getPreferences().is3dEnabled() ){
//this button lets them turn GL on without going to the preference menu.
final JButton enable = new JButton(trans.get("RocketPanel.3DDisabledMessageButton"));
enable.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Application.getPreferences().set3dEnabled(true);
panel.remove(enable);
panel.revalidate();
panel.repaint();
}
});
panel.add(enable);
}
this.add(panel);
}
private void initGLCanvas() {
log.debug("Initializing RocketFigure3D OpenGL Canvas");
OpenGLUtils.enterDangerZone();
try {
log.debug("Setting up GL capabilities...");
@ -139,7 +165,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
log.verbose("GL - Setting up mouse listeners");
setupMouseListeners();
log.verbose("GL - Rasterizine Carets"); //reticulating splines?
log.verbose("GL - Rasterizing Carets"); //reticulating splines?
rasterizeCarets();
} catch (Throwable t) {
@ -147,6 +173,8 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
canvas = null;
this.add(new JLabel("Unable to load 3d Libraries: "
+ t.getMessage()));
} finally {
OpenGLUtils.exitDangerZone();
}
}
@ -285,6 +313,8 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
drawExtras(gl, glu);
drawCarets(gl, glu);
OpenGLUtils.exitDangerZone();
}
@ -567,7 +597,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
glu.gluProject(c.x, c.y, c.z, mvmatrix, 0, projmatrix, 0, viewport, 0,
out, 0);
log.verbose("GL - peoject() complete");
log.verbose("GL - project() complete");
return new Coordinate(out[0], out[1], out[2]);
}

View File

@ -285,7 +285,6 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
}
});
bg.add(toggle3d);
toggle3d.setEnabled(RocketFigure3d.is3dEnabled());
add(toggle3d, "gap rel");
// Zoom level selector

View File

@ -49,6 +49,7 @@ public abstract class Preferences {
// Node names
public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN";
private static final String THREE_D_ENABLED = "THREE_D_ENABLED";
/*
* ******************************************************************************************
@ -115,6 +116,22 @@ public abstract class Preferences {
return this.getBoolean(AUTO_OPEN_LAST_DESIGN, false);
}
/**
* Enable/Disable the 3d functionality
* @param enabled
*/
public final void set3dEnabled(boolean enabled){
this.putBoolean(THREE_D_ENABLED, enabled);
}
/**
*
* @return true if 3d is enabled.
*/
public final boolean is3dEnabled(){
return this.getBoolean(THREE_D_ENABLED, true);
}
/**
* Return the OpenRocket unique ID.
*

View File

@ -4,6 +4,7 @@ import java.io.PrintStream;
import java.util.Locale;
import java.util.prefs.Preferences;
import net.sf.openrocket.gui.figure3d.OpenGLUtils;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.L10N;
@ -51,6 +52,8 @@ public class Startup {
Application.setPreferences( new SwingPreferences() );
OpenGLUtils.earlyInitialize();
// Setup the translations
initializeL10n();