diff --git a/core/resources/datafiles/examples/Apocalypse with decals.ork b/core/resources/datafiles/examples/Apocalypse with decals.ork index 235096add..9150c47d8 100644 Binary files a/core/resources/datafiles/examples/Apocalypse with decals.ork and b/core/resources/datafiles/examples/Apocalypse with decals.ork differ diff --git a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java index 2341908ec..cfb95f636 100644 --- a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java +++ b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java @@ -26,6 +26,8 @@ public class AppearanceBuilder extends AbstractChangeSource { private double rotation; private String image; private Decal.EdgeMode edgeMode; + + private boolean batch; public AppearanceBuilder() { resetToDefaults(); @@ -217,7 +219,15 @@ public class AppearanceBuilder extends AbstractChangeSource { @Override protected void fireChangeEvent() { - super.fireChangeEvent(); + if ( !batch ) + super.fireChangeEvent(); + } + + public void batch(Runnable r){ + batch = true; + r.run(); + batch = false; + fireChangeEvent(); } } diff --git a/core/src/net/sf/openrocket/appearance/SimpleAppearanceBuilder.java b/core/src/net/sf/openrocket/appearance/SimpleAppearanceBuilder.java new file mode 100644 index 000000000..0575069d8 --- /dev/null +++ b/core/src/net/sf/openrocket/appearance/SimpleAppearanceBuilder.java @@ -0,0 +1,77 @@ +package net.sf.openrocket.appearance; + +import net.sf.openrocket.util.Color; + +public class SimpleAppearanceBuilder extends AppearanceBuilder { + + public SimpleAppearanceBuilder() { + super(); + } + + public SimpleAppearanceBuilder(Appearance a) { + super(a); + } + + public Color getColor() { + return getDiffuse(); + } + + public void setColor(final Color c) { + batch(new Runnable() { + @Override + public void run() { + setAmbient(c); + setDiffuse(c); + } + }); + } + + public void setShine(final int s) { + batch(new Runnable() { + @Override + public void run() { + setShininess(s); + int c = (int) (s * 2.55); + setSpecular(new net.sf.openrocket.util.Color(c, c, c)); + } + }); + } + + public int getShine() { + return getShininess(); + } + + private Color oldColor = null; + + @Override + public void setImage(final String image) { + batch(new Runnable() { + @Override + public void run() { + if (getImage() == null && image != null) { + oldColor = getColor(); + setColor(new Color(255, 255, 255)); + } else if (getImage() != null && image == null && oldColor != null) { + setColor(oldColor); + } + SimpleAppearanceBuilder.super.setImage(image); + } + }); + } + + public double getScaleX() { + return 1.0 / super.getScaleU(); + } + + public void setScaleX(double scaleU) { + super.setScaleU(1.0 / scaleU); + } + + public double getScaleY() { + return 1.0 / super.getScaleV(); + } + + public void setScaleY(double scaleV) { + super.setScaleV(1.0 / scaleV); + } +} diff --git a/core/src/net/sf/openrocket/document/DecalRegistry.java b/core/src/net/sf/openrocket/document/DecalRegistry.java index f3d2f8dbe..4a7c3b4b1 100644 --- a/core/src/net/sf/openrocket/document/DecalRegistry.java +++ b/core/src/net/sf/openrocket/document/DecalRegistry.java @@ -15,10 +15,13 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import net.sf.openrocket.file.FileInfo; +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.FileUtils; public class DecalRegistry { + private static LogHelper log = Application.getLogger(); private FileInfo fileInfo; private boolean isZipFile = false; @@ -105,7 +108,12 @@ public class DecalRegistry { if ( rawIs == null ) { File decal = new File(name); if ( decal.isAbsolute() ) { - rawIs = new FileInputStream(decal); + try { + rawIs = new FileInputStream(decal); + } catch ( FileNotFoundException e ){ + name = decal.getName(); + log.debug("Unable to find absolute file" + decal + ", falling back to " + name); + } } } diff --git a/core/src/net/sf/openrocket/gui/adaptors/IntegerModel.java b/core/src/net/sf/openrocket/gui/adaptors/IntegerModel.java index e948918af..3b07d9054 100644 --- a/core/src/net/sf/openrocket/gui/adaptors/IntegerModel.java +++ b/core/src/net/sf/openrocket/gui/adaptors/IntegerModel.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.EventListener; import java.util.EventObject; +import javax.swing.BoundedRangeModel; +import javax.swing.DefaultBoundedRangeModel; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; @@ -83,7 +85,44 @@ public class IntegerModel implements StateChangeListener { return new IntegerSpinnerModel(); } + private class ValueSliderModel extends DefaultBoundedRangeModel implements BoundedRangeModel, StateChangeListener { + ValueSliderModel(){ + super(IntegerModel.this.getValue(), 0, minValue, maxValue); + } + @Override + public void setValue(int newValue) { + IntegerModel.this.setValue(newValue); + } + + @Override + public int getValue(){ + return IntegerModel.this.getValue(); + } + @Override + public void stateChanged(EventObject e) { + IntegerModel.this.fireStateChanged(); + } + + @Override + public void addChangeListener(ChangeListener l) { + IntegerModel.this.addChangeListener(l); + } + + @Override + public void removeChangeListener(ChangeListener l) { + IntegerModel.this.removeChangeListener(l); + } + + } + /** + * Returns a new BoundedRangeModel with the same base as the IntegerModel. + * + * @return A compatibility layer for Sliders. + */ + public BoundedRangeModel getSliderModel(){ + return new ValueSliderModel(); + } //////////// Main model ///////////// diff --git a/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java index 37c628edf..4d86ae005 100644 --- a/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java +++ b/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java @@ -14,12 +14,13 @@ import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSeparator; +import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.SwingConstants; import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.appearance.AppearanceBuilder; import net.sf.openrocket.appearance.Decal.EdgeMode; +import net.sf.openrocket.appearance.SimpleAppearanceBuilder; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.SpinnerEditor; import net.sf.openrocket.gui.adaptors.BooleanModel; @@ -46,7 +47,7 @@ import net.sf.openrocket.util.StateChangeListener; public class AppearancePanel extends JPanel { private static final Translator trans = Application.getTranslator(); - private AppearanceBuilder ab; + private SimpleAppearanceBuilder ab; private final static UnitGroup UNIT_FOR_SCALES = new UnitGroup(); static { @@ -108,16 +109,19 @@ public class AppearancePanel extends JPanel { public AppearancePanel(final OpenRocketDocument document, final RocketComponent c) { super(new MigLayout("fill", "[150][grow][150][grow]")); - ab = new AppearanceBuilder(c.getAppearance()); + ab = new SimpleAppearanceBuilder(c.getAppearance()); net.sf.openrocket.util.Color figureColor = c.getColor(); if (figureColor == null) { figureColor = Application.getPreferences().getDefaultColor(c.getClass()); } final JButton figureColorButton = new JButton(new ColorIcon(figureColor)); - final JButton diffuseColorButton = new JButton(new ColorIcon(ab.getDiffuse())); + + /*final JButton diffuseColorButton = new JButton(new ColorIcon(ab.getDiffuse())); final JButton ambientColorButton = new JButton(new ColorIcon(ab.getAmbient())); - final JButton specularColorButton = new JButton(new ColorIcon(ab.getSpecular())); + final JButton specularColorButton = new JButton(new ColorIcon(ab.getSpecular()));*/ + + final JButton colorButton = new JButton(new ColorIcon(ab.getAmbient())); final JComboBox textureDropDown = new JComboBox( new DecalModel(this,document,ab));; @@ -125,9 +129,10 @@ public class AppearancePanel extends JPanel { @Override public void stateChanged(EventObject e) { figureColorButton.setIcon(new ColorIcon(c.getColor())); - diffuseColorButton.setIcon(new ColorIcon(ab.getDiffuse())); + /*diffuseColorButton.setIcon(new ColorIcon(ab.getDiffuse())); ambientColorButton.setIcon(new ColorIcon(ab.getAmbient())); - specularColorButton.setIcon(new ColorIcon(ab.getSpecular())); + specularColorButton.setIcon(new ColorIcon(ab.getSpecular()));*/ + colorButton.setIcon(new ColorIcon(ab.getColor())); c.setAppearance(ab.getAppearance()); } }); @@ -144,9 +149,10 @@ public class AppearancePanel extends JPanel { }); figureColorButton.addActionListener(new ColorActionListener(c, "Color")); - diffuseColorButton.addActionListener(new ColorActionListener(ab, "Diffuse")); + colorButton.addActionListener(new ColorActionListener(ab, "Color")); + /*diffuseColorButton.addActionListener(new ColorActionListener(ab, "Diffuse")); ambientColorButton.addActionListener(new ColorActionListener(ab, "Ambient")); - specularColorButton.addActionListener(new ColorActionListener(ab, "Specular")); + specularColorButton.addActionListener(new ColorActionListener(ab, "Specular"));*/ BooleanModel mDefault = new BooleanModel(c.getAppearance() == null); BooleanModel fDefault = new BooleanModel(c.getColor() == null); @@ -213,7 +219,7 @@ public class AppearancePanel extends JPanel { add(new JSeparator(SwingConstants.HORIZONTAL), "span, wrap, growx"); {// Texture Header Row - add(new StyledLabel(trans.get("AppearanceCfg.lbl.Appearance"), Style.BOLD)); + add(new StyledLabel(trans.get("AppearanceCfg.lbl.Appearance"), Style.BOLD), "wrap"); final JCheckBox materialDefault = new JCheckBox(mDefault); materialDefault.addActionListener(new ActionListener() { @@ -226,11 +232,6 @@ public class AppearancePanel extends JPanel { } } }); - materialDefault.setText(trans.get("AppearanceCfg.lbl.Usedefault")); - add(materialDefault); - JButton setMDefault = new JButton(trans.get("AppearanceCfg.but.savedefault")); - mDefault.addEnableComponent(setMDefault, false); - add(setMDefault, "span 2, align right, wrap"); } {// Texture File @@ -241,34 +242,47 @@ public class AppearancePanel extends JPanel { add(p, "span 3, growx, wrap"); } - { // Diffuse + /*{ // Diffuse add(new JLabel(trans.get("AppearanceCfg.lbl.color.diffuse"))); mDefault.addEnableComponent(diffuseColorButton, false); add(diffuseColorButton); + }*/ + + { // Color + add(new JLabel("Color")); + mDefault.addEnableComponent(colorButton, false); + add(colorButton); } { // Scale add(new JLabel(trans.get("AppearanceCfg.lbl.texture.scale"))); add(new JLabel("x:"), "split 4"); - JSpinner scaleU = new JSpinner(new DoubleModel(ab, "ScaleU",UNIT_FOR_SCALES).getSpinnerModel()); + JSpinner scaleU = new JSpinner(new DoubleModel(ab, "ScaleX",UNIT_FOR_SCALES).getSpinnerModel()); scaleU.setEditor(new SpinnerEditor(scaleU)); mDefault.addEnableComponent(scaleU, false); add(scaleU, "w 40"); add(new JLabel("y:")); - JSpinner scaleV = new JSpinner(new DoubleModel(ab, "ScaleV",UNIT_FOR_SCALES).getSpinnerModel()); + JSpinner scaleV = new JSpinner(new DoubleModel(ab, "ScaleY",UNIT_FOR_SCALES).getSpinnerModel()); scaleV.setEditor(new SpinnerEditor(scaleV)); mDefault.addEnableComponent(scaleV, false); add(scaleV, "wrap, w 40"); } - - { // Ambient - add(new JLabel(trans.get("AppearanceCfg.lbl.color.ambient"))); - mDefault.addEnableComponent(ambientColorButton, false); - add(ambientColorButton); + + {// Placeholder + add(new JLabel(trans.get("AppearanceCfg.lbl.shine"))); + IntegerModel shineModel = new IntegerModel(ab, "Shine", 0, 100); + JSpinner spin = new JSpinner(shineModel.getSpinnerModel()); + JSlider slide = new JSlider(shineModel.getSliderModel()); + mDefault.addEnableComponent(slide, false); + mDefault.addEnableComponent(spin, false); + + add(spin, "split 2, w 50"); + add(slide, "w 100"); } + { // Offset add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset"))); @@ -284,36 +298,16 @@ public class AppearancePanel extends JPanel { mDefault.addEnableComponent(offsetV, false); add(offsetV, "wrap, w 40"); } - - { // Specular - add(new JLabel(trans.get("AppearanceCfg.lbl.color.specular"))); - mDefault.addEnableComponent(specularColorButton, false); - add(specularColorButton); + + { // Repeat + add(new JLabel(trans.get("AppearanceCfg.lbl.texture.repeat"))); + EdgeMode[] list = new EdgeMode[EdgeMode.values().length + 1]; + System.arraycopy(EdgeMode.values(), 0, list, 1, EdgeMode.values().length); + JComboBox combo = new JComboBox(new EnumModel(ab, "EdgeMode", list)); + mDefault.addEnableComponent(combo, false); + add(combo); } - { // Center - add(new JLabel(trans.get("AppearanceCfg.lbl.texture.center"))); - - add(new JLabel("x:"), "split 4"); - JSpinner centerU = new JSpinner(new DoubleModel(ab, "CenterU").getSpinnerModel()); - centerU.setEditor(new SpinnerEditor(centerU)); - mDefault.addEnableComponent(centerU, false); - add(centerU, "w 40"); - - add(new JLabel("y:")); - JSpinner centerV = new JSpinner(new DoubleModel(ab, "CenterV").getSpinnerModel()); - centerV.setEditor(new SpinnerEditor(centerV)); - mDefault.addEnableComponent(centerV, false); - add(centerV, "wrap, w 40"); - } - - { // Shine - add(new JLabel(trans.get("AppearanceCfg.lbl.shine"))); - IntegerModel shineModel = new IntegerModel(ab, "Shininess", 0, 128); - JSpinner shine = new JSpinner(shineModel.getSpinnerModel()); - mDefault.addEnableComponent(shine, false); - add(shine, "w 50"); - } { // Rotation add(new JLabel(trans.get("AppearanceCfg.lbl.texture.rotation"))); @@ -328,18 +322,6 @@ public class AppearancePanel extends JPanel { add(bs, "w 100, wrap"); } - {// Placeholder - add(new JLabel(""), "span 2"); - } - - { // Repeat - add(new JLabel(trans.get("AppearanceCfg.lbl.texture.repeat"))); - EdgeMode[] list = new EdgeMode[EdgeMode.values().length + 1]; - System.arraycopy(EdgeMode.values(), 0, list, 1, EdgeMode.values().length); - JComboBox combo = new JComboBox(new EnumModel(ab, "EdgeMode", list)); - mDefault.addEnableComponent(combo, false); - add(combo); - } } diff --git a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java b/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java index 594f510b3..d624ca17a 100644 --- a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java +++ b/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java @@ -5,6 +5,7 @@ import java.util.HashMap; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GL2ES1; +import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.fixedfunc.GLLightingFunc; import net.sf.openrocket.rocketcomponent.BodyTube; @@ -97,7 +98,29 @@ public class FigureRenderStrategy extends RenderStrategy { } + @Override + public void init(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + + gl.glLightModelfv(GL2ES1.GL_LIGHT_MODEL_AMBIENT, + new float[] { 0,0,0 }, 0); + float amb = 0.3f; + float dif = 1.0f - amb; + float spc = 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[] { spc, spc, spc, 1 }, 0); + + gl.glEnable(GLLightingFunc.GL_LIGHT1); + gl.glEnable(GLLightingFunc.GL_LIGHTING); + gl.glShadeModel(GLLightingFunc.GL_SMOOTH); + + gl.glEnable(GLLightingFunc.GL_NORMALIZE); + } private static int getShine(RocketComponent c) { if (c instanceof ExternalComponent) { diff --git a/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java index 22b8ccbb7..336188a2c 100644 --- a/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java +++ b/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java @@ -131,20 +131,22 @@ public class RocketRenderer { gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0); gl.glLineWidth(5.0f); - for (RocketComponent c : selection) { - //Draw as lines, set Z to nearest - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE); - gl.glDepthRange(0, 0); - cr.renderGeometry(gl, c); - - //Draw polygons, always passing depth test, - //setting Z to farthest - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL); - gl.glDepthRange(1, 1); - gl.glDepthFunc(GL.GL_ALWAYS); - cr.renderGeometry(gl, c); - gl.glDepthFunc(GL.GL_LESS); - gl.glDepthRange(0, 1); + for (RocketComponent c : configuration) { + if ( selection.contains(c) ){ + //Draw as lines, set Z to nearest + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE); + gl.glDepthRange(0, 0); + cr.renderGeometry(gl, c); + + //Draw polygons, always passing depth test, + //setting Z to farthest + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL); + gl.glDepthRange(1, 1); + gl.glDepthFunc(GL.GL_ALWAYS); + cr.renderGeometry(gl, c); + gl.glDepthFunc(GL.GL_LESS); + gl.glDepthRange(0, 1); + } } gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,