Further refactre RenderStrategies into RocketRenderer subclasses
This commit is contained in:
parent
a857fb93be
commit
143a032728
@ -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<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Texture> oldTexCache = new HashMap<String, Texture>();
|
||||
private Map<String, Texture> texCache = new HashMap<String, Texture>();
|
||||
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<String,Texture>();
|
||||
texCache = new HashMap<String,Texture>();
|
||||
|
||||
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<String, Texture> e : oldTexCache.entrySet()) {
|
||||
log.debug("Destroying Texture for " + e.getKey());
|
||||
if (e.getValue() != null)
|
||||
e.getValue().destroy(gl);
|
||||
}
|
||||
oldTexCache = texCache;
|
||||
texCache = new HashMap<String, Texture>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, Texture> oldTexCache = new HashMap<String, Texture>();
|
||||
private Map<String, Texture> texCache = new HashMap<String, Texture>();
|
||||
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<String, Texture>();
|
||||
texCache = new HashMap<String, Texture>();
|
||||
|
||||
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<String, Texture> e : oldTexCache.entrySet()) {
|
||||
log.debug("Destroying Texture for " + e.getKey());
|
||||
if (e.getValue() != null)
|
||||
e.getValue().destroy(gl);
|
||||
}
|
||||
oldTexCache = texCache;
|
||||
texCache = new HashMap<String, Texture>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -24,55 +24,50 @@ import net.sf.openrocket.util.Coordinate;
|
||||
* @author Bill Kuker <bkuker@billkuker.com>
|
||||
*/
|
||||
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<RocketComponent> 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<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),
|
||||
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<RocketComponent> selection) {
|
||||
|
||||
|
||||
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 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<MotorMount> 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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user