From 143a032728f91c0d1bb7215fa1c982ab4153ab8e Mon Sep 17 00:00:00 2001 From: bkuker Date: Wed, 2 Jan 2013 12:29:33 -0500 Subject: [PATCH] Further refactre RenderStrategies into RocketRenderer subclasses --- .../gui/figure3d/FigureRenderStrategy.java | 123 --------- .../gui/figure3d/FigureRenderer.java | 125 ++++++++- .../gui/figure3d/RealisticRenderStrategy.java | 238 ------------------ .../gui/figure3d/RealisticRenderer.java | 228 ++++++++++++++++- .../gui/figure3d/RenderStrategy.java | 27 -- .../gui/figure3d/RocketRenderer.java | 122 ++++----- 6 files changed, 390 insertions(+), 473 deletions(-) delete mode 100644 core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java delete mode 100644 core/src/net/sf/openrocket/gui/figure3d/RealisticRenderStrategy.java delete mode 100644 core/src/net/sf/openrocket/gui/figure3d/RenderStrategy.java diff --git a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java b/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java deleted file mode 100644 index e661a34cc..000000000 --- a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderStrategy.java +++ /dev/null @@ -1,123 +0,0 @@ -package net.sf.openrocket.gui.figure3d; - -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.ExternalComponent; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.Color; - -public class FigureRenderStrategy extends RenderStrategy { - private final float[] color = new float[4]; - - public FigureRenderStrategy() { - super(null); - } - - private static final HashMap, Color> defaultColorCache = new HashMap, Color>(); - - public void preGeometry(GL2 gl, RocketComponent c, float alpha) { - gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1); - Color figureColor = c.getColor(); - if (figureColor == null) { - if (defaultColorCache.containsKey(c.getClass())) { - figureColor = defaultColorCache.get(c.getClass()); - } else { - figureColor = Application.getPreferences().getDefaultColor(c.getClass()); - defaultColorCache.put(c.getClass(), figureColor); - } - } - - // Set up the front A&D color - convertColor(figureColor, color); - color[3] = alpha; - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0); - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0); - - // Set up the Specular color & Shine - convertColor(figureColor, color); - float d = 0.9f; - float m = (float) getShine(c) / 128.0f; - color[0] = Math.max(color[0], d) * m; - color[1] = Math.max(color[1], d) * m; - color[2] = Math.max(color[2], d) * m; - - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0); - gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, getShine(c)); - - color[0] = color[1] = color[2] = 0; - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_SPECULAR, color, 0); - - //Back A&D - convertColor(figureColor, color); - color[0] = color[0] * 0.4f; - color[1] = color[1] * 0.4f; - color[2] = color[2] * 0.4f; - color[3] = alpha; - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0); - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0); - - } - - @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) { - switch (((ExternalComponent) c).getFinish()) { - case ROUGH: - return 10; - case UNFINISHED: - return 30; - case NORMAL: - return 40; - case SMOOTH: - return 80; - case POLISHED: - return 128; - default: - return 100; - } - } - return 20; - } - - protected static void convertColor(Color color, float[] out) { - if ( color == null ){ - out[0] = 1; - out[1] = 1; - out[2] = 0; - } else { - out[0] = Math.max(0.2f, (float) color.getRed() / 255f) * 2; - out[1] = Math.max(0.2f, (float) color.getGreen() / 255f) * 2; - out[2] = Math.max(0.2f, (float) color.getBlue() / 255f) * 2; - } - } -} diff --git a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/FigureRenderer.java index 228288085..f6c230099 100644 --- a/core/src/net/sf/openrocket/gui/figure3d/FigureRenderer.java +++ b/core/src/net/sf/openrocket/gui/figure3d/FigureRenderer.java @@ -1,25 +1,56 @@ package net.sf.openrocket.gui.figure3d; +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; +import net.sf.openrocket.rocketcomponent.ExternalComponent; 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; public class FigureRenderer extends RocketRenderer { - - protected FigureRenderer() { - super(new FigureRenderStrategy()); + private final float[] color = new float[4]; + + public FigureRenderer() { } - + @Override - public void renderComponent(GL2 gl, RocketComponent c, float alpha) { - ((FigureRenderStrategy)currentStrategy).preGeometry(gl, c, alpha); - cr.renderGeometry(gl, c); + public void init(GLAutoDrawable drawable) { + super.init(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); } + + @Override public boolean isDrawn(RocketComponent c) { return true; @@ -41,4 +72,84 @@ public class FigureRenderer extends RocketRenderer { } return false; } + + private static final HashMap, Color> defaultColorCache = new HashMap, Color>(); + + @Override + public void renderComponent(GL2 gl, RocketComponent c, float alpha) { + + gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1); + Color figureColor = c.getColor(); + if (figureColor == null) { + if (defaultColorCache.containsKey(c.getClass())) { + figureColor = defaultColorCache.get(c.getClass()); + } else { + figureColor = Application.getPreferences().getDefaultColor(c.getClass()); + defaultColorCache.put(c.getClass(), figureColor); + } + } + + // Set up the front A&D color + convertColor(figureColor, color); + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0); + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0); + + // Set up the Specular color & Shine + convertColor(figureColor, color); + float d = 0.9f; + float m = (float) getShine(c) / 128.0f; + color[0] = Math.max(color[0], d) * m; + color[1] = Math.max(color[1], d) * m; + color[2] = Math.max(color[2], d) * m; + + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0); + gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, getShine(c)); + + color[0] = color[1] = color[2] = 0; + gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_SPECULAR, color, 0); + + //Back A&D + convertColor(figureColor, color); + color[0] = color[0] * 0.4f; + color[1] = color[1] * 0.4f; + color[2] = color[2] * 0.4f; + color[3] = alpha; + 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 static int getShine(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; + default: + return 100; + } + } + return 20; + } + + protected static void convertColor(Color color, float[] out) { + if ( color == null ){ + out[0] = 1; + out[1] = 1; + out[2] = 0; + } else { + out[0] = Math.max(0.2f, (float) color.getRed() / 255f) * 2; + out[1] = Math.max(0.2f, (float) color.getGreen() / 255f) * 2; + out[2] = Math.max(0.2f, (float) color.getBlue() / 255f) * 2; + } + } } diff --git a/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderStrategy.java b/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderStrategy.java deleted file mode 100644 index 53ab2d47f..000000000 --- a/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderStrategy.java +++ /dev/null @@ -1,238 +0,0 @@ -package net.sf.openrocket.gui.figure3d; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES1; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLProfile; -import javax.media.opengl.fixedfunc.GLLightingFunc; -import javax.media.opengl.fixedfunc.GLMatrixFunc; - -import net.sf.openrocket.appearance.Appearance; -import net.sf.openrocket.appearance.Decal; -import net.sf.openrocket.document.DecalRegistry; -import net.sf.openrocket.document.OpenRocketDocument; -import net.sf.openrocket.logging.LogHelper; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.Color; - -import com.jogamp.opengl.util.texture.Texture; -import com.jogamp.opengl.util.texture.TextureData; -import com.jogamp.opengl.util.texture.TextureIO; - -public class RealisticRenderStrategy extends RenderStrategy { - - private final float[] colorBlack = { 0, 0, 0, 1 }; - private final float[] color = new float[4]; - private static final LogHelper log = Application.getLogger(); - - private final DecalRegistry decalLoader; - private boolean needClearCache = false; - private Map oldTexCache = new HashMap(); - private Map texCache = new HashMap(); - private float anisotrophy = 0; - - public RealisticRenderStrategy(OpenRocketDocument document) { - super(document); - this.decalLoader = document.getDecalRegistry(); - } - - @Override - public void updateFigure() { - needClearCache = true; - } - - @Override - public void init(GLAutoDrawable drawable) { - oldTexCache = new HashMap(); - texCache = new HashMap(); - - 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); - - if (gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic")) { - float a[] = new float[1]; - gl.glGetFloatv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, a, 0); - anisotrophy = a[0]; - } - } - - @Override - public void dispose(GLAutoDrawable drawable) { - oldTexCache = null; - texCache = null; - } - - public void preGeometry(GL2 gl, RocketComponent c, float alpha) { - if (needClearCache) { - clearCaches(gl); - needClearCache = false; - } - - Appearance a = getAppearance(c); - gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1); - gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL,GL2.GL_SEPARATE_SPECULAR_COLOR); - - - convertColor(a.getDiffuse(), color); - color[3] = alpha; - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0); - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0); - - convertColor(a.getAmbient(), color); - color[3] = alpha; - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0); - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0); - - convertColor(a.getSpecular(), color); - color[3] = alpha; - gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0); - gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, a.getShininess()); - - gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0); - gl.glMateriali(GL.GL_BACK, GLLightingFunc.GL_SHININESS, 0); - - Decal t = a.getTexture(); - Texture tex = null; - if (t != null) { - tex = getTexture(t); - } - if (t != null && tex != null) { - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); - - tex.enable(gl); - tex.bind(gl); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - - gl.glTranslated(-t.getCenter().x, -t.getCenter().y, 0); - gl.glRotated(57.2957795 * t.getRotation(), 0, 0, 1); - gl.glTranslated(t.getCenter().x, t.getCenter().y, 0); - - gl.glScaled(t.getScale().x, t.getScale().y, 0); - gl.glTranslated(t.getOffset().x, t.getOffset().y, 0); - - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, toEdgeMode(t.getEdgeMode())); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, toEdgeMode(t.getEdgeMode())); - - gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - - if ( anisotrophy > 0){ - gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotrophy); - } - } - } - - public void postGeometry(GL2 gl, RocketComponent c, float alpha) { - Appearance a = getAppearance(c); - Decal t = a.getTexture(); - Texture tex = null; - if (t != null) { - tex = getTexture(t); - } - if (tex != null) { - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - tex.disable(gl); - } - } - - private void clearCaches(GL2 gl) { - log.debug("ClearCaches"); - for (Map.Entry e : oldTexCache.entrySet()) { - log.debug("Destroying Texture for " + e.getKey()); - if (e.getValue() != null) - e.getValue().destroy(gl); - } - oldTexCache = texCache; - texCache = new HashMap(); - } - - private Texture getTexture(Decal t) { - String imageName = t.getImage(); - - // Return the Cached value if available - if (texCache.containsKey(imageName)) - return texCache.get(imageName); - - // If the texture is in the Old Cache, save it. - if (oldTexCache.containsKey(imageName)) { - texCache.put(imageName, oldTexCache.get(imageName)); - oldTexCache.remove(imageName); - return texCache.get(imageName); - } - - // Otherwise load it. - Texture tex = null; - try { - log.debug("Loading texture " + t); - InputStream is = decalLoader.getDecal(imageName); - TextureData data = TextureIO.newTextureData(GLProfile.getDefault(), is, true, null); - tex = TextureIO.newTexture(data); - } catch (Throwable e) { - log.error("Error loading Texture", e); - } - texCache.put(imageName, tex); - - return tex; - - } - - private Appearance getAppearance(RocketComponent c) { - Appearance ret = c.getAppearance(); - if (ret == null) { - ret = Appearance.MISSING; - } - return ret; - } - - private int toEdgeMode(Decal.EdgeMode m) { - switch (m) { - case REPEAT: - return GL.GL_REPEAT; - case MIRROR: - return GL.GL_MIRRORED_REPEAT; - case CLAMP: - return GL.GL_CLAMP_TO_EDGE; - default: - return GL.GL_CLAMP_TO_EDGE; - } - } - - protected static void convertColor(Color color, float[] out) { - if (color == null) { - out[0] = 1; - out[1] = 1; - out[2] = 0; - } else { - out[0] = (float) color.getRed() / 255f; - out[1] = (float) color.getGreen() / 255f; - out[2] = (float) color.getBlue() / 255f; - } - } -} diff --git a/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java index c57aa95ad..86f232896 100644 --- a/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java +++ b/core/src/net/sf/openrocket/gui/figure3d/RealisticRenderer.java @@ -1,22 +1,87 @@ package net.sf.openrocket.gui.figure3d; -import javax.media.opengl.GL2; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLProfile; +import javax.media.opengl.fixedfunc.GLLightingFunc; +import javax.media.opengl.fixedfunc.GLMatrixFunc; + +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.Decal; +import net.sf.openrocket.document.DecalRegistry; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.util.Color; + +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; public class RealisticRenderer extends RocketRenderer { - public RealisticRenderer(OpenRocketDocument doc) { - super(new RealisticRenderStrategy(doc)); + private final float[] colorBlack = { 0, 0, 0, 1 }; + private final float[] color = new float[4]; + + private final DecalRegistry decalLoader; + private boolean needClearCache = false; + private Map oldTexCache = new HashMap(); + private Map texCache = new HashMap(); + private float anisotrophy = 0; + + public RealisticRenderer(OpenRocketDocument document) { + this.decalLoader = document.getDecalRegistry(); } - + @Override - public void renderComponent(GL2 gl, RocketComponent c, float alpha) { - ((RealisticRenderStrategy)currentStrategy).preGeometry(gl, c, alpha); - cr.renderGeometry(gl, c); - ((RealisticRenderStrategy)currentStrategy).postGeometry(gl, c, alpha); + public void init(GLAutoDrawable drawable) { + super.init(drawable); + + oldTexCache = new HashMap(); + texCache = new HashMap(); + + 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); + + if (gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic")) { + float a[] = new float[1]; + gl.glGetFloatv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, a, 0); + anisotrophy = a[0]; + } + } + + @Override + public void updateFigure() { + super.updateFigure(); + + needClearCache = true; + } + + @Override + public void dispose(GLAutoDrawable drawable) { + super.dispose(drawable); + + oldTexCache = null; + texCache = null; } - @Override public boolean isDrawn(RocketComponent c) { @@ -28,4 +93,149 @@ public class RealisticRenderer extends RocketRenderer { return false; } + @Override + public void renderComponent(GL2 gl, RocketComponent c, float alpha) { + + if (needClearCache) { + clearCaches(gl); + needClearCache = false; + } + + final Appearance a = getAppearance(c); + final Decal t = a.getTexture(); + final Texture tex = getTexture(t); + + gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1); + gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); + + convertColor(a.getDiffuse(), color); + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0); + gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0); + + convertColor(a.getAmbient(), color); + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0); + gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0); + + convertColor(a.getSpecular(), color); + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0); + gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, a.getShininess()); + + gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0); + gl.glMateriali(GL.GL_BACK, GLLightingFunc.GL_SHININESS, 0); + + if (t != null && tex != null) { + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + + tex.enable(gl); + tex.bind(gl); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPushMatrix(); + + gl.glTranslated(-t.getCenter().x, -t.getCenter().y, 0); + gl.glRotated(57.2957795 * t.getRotation(), 0, 0, 1); + gl.glTranslated(t.getCenter().x, t.getCenter().y, 0); + + gl.glScaled(t.getScale().x, t.getScale().y, 0); + gl.glTranslated(t.getOffset().x, t.getOffset().y, 0); + + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, toEdgeMode(t.getEdgeMode())); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, toEdgeMode(t.getEdgeMode())); + + gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + + if (anisotrophy > 0) { + gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotrophy); + } + } + + cr.renderGeometry(gl, c); + + if (tex != null) { + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPopMatrix(); + gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + tex.disable(gl); + } + } + + private void clearCaches(GL2 gl) { + log.debug("ClearCaches"); + for (Map.Entry e : oldTexCache.entrySet()) { + log.debug("Destroying Texture for " + e.getKey()); + if (e.getValue() != null) + e.getValue().destroy(gl); + } + oldTexCache = texCache; + texCache = new HashMap(); + } + + private Texture getTexture(Decal t) { + if (t == null) + return null; + + String imageName = t.getImage(); + + // Return the Cached value if available + if (texCache.containsKey(imageName)) + return texCache.get(imageName); + + // If the texture is in the Old Cache, save it. + if (oldTexCache.containsKey(imageName)) { + texCache.put(imageName, oldTexCache.get(imageName)); + oldTexCache.remove(imageName); + return texCache.get(imageName); + } + + // Otherwise load it. + Texture tex = null; + try { + log.debug("Loading texture " + t); + InputStream is = decalLoader.getDecal(imageName); + TextureData data = TextureIO.newTextureData(GLProfile.getDefault(), is, true, null); + tex = TextureIO.newTexture(data); + } catch (Throwable e) { + log.error("Error loading Texture", e); + } + texCache.put(imageName, tex); + + return tex; + + } + + private Appearance getAppearance(RocketComponent c) { + Appearance ret = c.getAppearance(); + if (ret == null) { + ret = Appearance.MISSING; + } + return ret; + } + + private int toEdgeMode(Decal.EdgeMode m) { + switch (m) { + case REPEAT: + return GL.GL_REPEAT; + case MIRROR: + return GL.GL_MIRRORED_REPEAT; + case CLAMP: + return GL.GL_CLAMP_TO_EDGE; + default: + return GL.GL_CLAMP_TO_EDGE; + } + } + + protected static void convertColor(Color color, float[] out) { + if (color == null) { + out[0] = 1; + out[1] = 1; + out[2] = 0; + } else { + out[0] = (float) color.getRed() / 255f; + out[1] = (float) color.getGreen() / 255f; + out[2] = (float) color.getBlue() / 255f; + } + } } diff --git a/core/src/net/sf/openrocket/gui/figure3d/RenderStrategy.java b/core/src/net/sf/openrocket/gui/figure3d/RenderStrategy.java deleted file mode 100644 index 68577a629..000000000 --- a/core/src/net/sf/openrocket/gui/figure3d/RenderStrategy.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.sf.openrocket.gui.figure3d; - -import javax.media.opengl.GLAutoDrawable; - -import net.sf.openrocket.document.OpenRocketDocument; - -public abstract class RenderStrategy { - - protected final OpenRocketDocument document; - - public RenderStrategy(OpenRocketDocument document) { - this.document = document; - } - - public void updateFigure() { - - } - - public void init(GLAutoDrawable drawable) { - - } - - public void dispose(GLAutoDrawable drawable) { - - } - -} diff --git a/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java index c2f4dbdb5..74be92755 100644 --- a/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java +++ b/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java @@ -24,55 +24,50 @@ import net.sf.openrocket.util.Coordinate; * @author Bill Kuker */ public abstract class RocketRenderer { - @SuppressWarnings("unused") - private static final LogHelper log = Application.getLogger(); - - final RenderStrategy currentStrategy; + protected static final LogHelper log = Application.getLogger(); + final ComponentRenderer cr = new ComponentRenderer(); - + private final float[] selectedEmissive = { 1, 0, 0, 1 }; private final float[] colorBlack = { 0, 0, 0, 1 }; - - protected RocketRenderer(RenderStrategy s){ - currentStrategy = s; - } - + public void init(GLAutoDrawable drawable) { cr.init(drawable); - currentStrategy.init(drawable); } - + public void dispose(GLAutoDrawable drawable) { - currentStrategy.dispose(drawable); } - + public void updateFigure() { - currentStrategy.updateFigure(); cr.updateFigure(); } - - - public RocketComponent pick(GLAutoDrawable drawable, - Configuration configuration, Point p, Set ignore) { + + public abstract void renderComponent(GL2 gl, RocketComponent c, float alpha); + + public abstract boolean isDrawn(RocketComponent c); + + public abstract boolean isDrawnTransparent(RocketComponent c); + + public RocketComponent pick(GLAutoDrawable drawable, Configuration 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) { 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), + 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); @@ -82,50 +77,46 @@ public abstract class RocketRenderer { 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); - + 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 selection) { - + + public void render(GLAutoDrawable drawable, Configuration configuration, Set 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 selection outline at nearest Z - gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION, - selectedEmissive, 0); + + { // Draw selection outline at nearest Z + 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.glLineWidth(5.0f); - + for (RocketComponent c : configuration) { - if ( selection.contains(c) ){ - //Draw as lines, set Z to nearest + 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 + + // 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); @@ -135,10 +126,9 @@ public abstract class RocketRenderer { } } gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL); - gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION, - colorBlack, 0); - } //done with selection outline - + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION, colorBlack, 0); + } // done with selection outline + // Draw all inner components for (RocketComponent c : configuration) { if (isDrawn(c)) { @@ -147,9 +137,9 @@ public abstract class RocketRenderer { } } } - + 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); @@ -162,7 +152,7 @@ public abstract class RocketRenderer { } } 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); @@ -176,9 +166,9 @@ public abstract class RocketRenderer { } gl.glDisable(GL.GL_BLEND); gl.glDisable(GL.GL_CULL_FACE); - + } - + private void renderMotors(GL2 gl, Configuration configuration) { String motorID = configuration.getFlightConfigurationID(); Iterator iterator = configuration.motorIterator(); @@ -187,21 +177,15 @@ public abstract class RocketRenderer { 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)); - + + 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 abstract void renderComponent(GL2 gl, RocketComponent c, float alpha); - public abstract boolean isDrawn(RocketComponent c); - - public abstract boolean isDrawnTransparent(RocketComponent c); }